如何调用未完全构造的对象的函数?

时间:2011-09-13 05:06:48

标签: c++ constructor

使用构造函数创建对象,以及正在构造的对象的调用函数:

class A
{
  public:
        A()
        {
        this->show();
        }   

        void show()
        {
        cout<<"show called!";
        }
};

现在我在main()创建对象,如下所示:

int main()
{
    A a;
    int xy;
    cin>>xy;
    return 0;
}

我怀疑当我使用构造函数创建对象时,如何在对象未完全构造时调用对象函数?

虚函数调用:

class A
{
  public:
        A()
        {

        }   

       virtual void show()
        {
        cout<<"show called!";
        }
};
class B:public A
{
      public: 
              B()
              {
                    A *a=this;
                    a->show();

                    }
             void show()
             {
                  cout<<"derived show";
                  }

      };


int main()
{
    A a;
    B b;
    int xy;
    cin>>xy;
    return 0;
}

正常输出:derived show

6 个答案:

答案 0 :(得分:4)

调用虚函数和非静态成员函数是可以的:

参见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf的第12.7节:

  

可以调用4个成员函数,包括虚函数(10.3)   在施工或毁坏期间(12.6.2)。

但是,在构造函数中使用虚函数时存在一些限制。这有点拗口:

  

直接或间接从a调用虚函数时   构造函数(包括mem-initializer或   用于非静态数据成员的支持或等于初始化程序)或来自   析构函数,以及调用适用的对象是对象   在建设或破坏中,所谓的功能是一个   在构造函数或析构函数自己的类中或在其中的一个中定义   base,但不是在派生自派生的类中重写它的函数   构造函数或析构函数的类,或者在其中一个中重写它   最派生对象的其他基类(1.8)。

我将上面的段落解释为所谓的虚函数不会出现在任何派生类中。这是有道理的,因为在执行阶段的这一点上,派生类中的任何构造函数都不会开始执行。

此外,第1部分规定了在施工开始后应使用非静态成员的限制。在您的示例中,构造开始后将调用成员,因此您不会违反第1部分:

  

1对于具有非平凡构造函数的对象,请参阅any   构造函数之前的对象的非静态成员或基类   开始执行导致未定义的行为。

答案 1 :(得分:1)

此代码完全合法。你可以调用方法 在类构造函数中。

所有常量(来自初始化列表)已经初始化,并且所有基类构造函数都被调用。

但是,您不应该在构造函数中调用虚方法。有关此限制,请参阅Scott Meyers说明。

答案 2 :(得分:1)

要考虑的是,在调用show()时,对象的哪些部分是构造的?

由于你从构造函数体内调用了show()(而不是从构造函数的初始化列表中调用),你可以放心,所有的A对象的成员变量都已经被构造了(因为那个在构造函数体之前发生了)执行)。

如果show()是一个虚方法,并且从A的子类的构造函数中调用A :: A(),那么你可能会惹恼你。在这种情况下,你可能希望show()调用B :: show(),但是这不会发生,因为B的vtable还没有设置(你最终会调用A :: show(),或者如果A :: show()会崩溃程序是一种纯虚方法)

答案 3 :(得分:0)

您正在调用部分构造的对象中的函数,如果此类函数处理类成员等,则可能导致错误行为。我不确定它是否调用未定义的行为,但我认为这不是一个好习惯。继承和虚函数使情况变得更糟!

在您的示例中,show可以声明为static,并且不会有调用它的风险。

答案 4 :(得分:0)

将一个类视为两个独立的部分:包含字段(变量)和方法(函数)的对象。给定类的方法独立于任何特定实例而存在,因此可以随时通过有效实例调用它,甚至是构造中期。

在构造函数运行之前,在实例化对象时“创建”字段。但是,它们没有设置值。因此,如果构造函数在字段初始化为合理值之前调用任何方法,那么您将会遇到一些未定义的行为。

如果必须在构造函数中调用方法,请务必尽可能多地将字段初始化为合理的值。

答案 5 :(得分:0)

  

我怀疑当我使用构造函数创建对象时,如何在对象未完全构造时调用对象函数?

在你的例子中发生的事情很好,只要你初始化你应该的位置(初始化列表)。您正在对已初始化成员的对象使用静态分派(具体而言,A没有要初始化的变量)。

那么什么是无效的?

  • 未正确初始化您的成员,或在真正初始化之前使用它们。不使用this来支持初始化列表。
  • 在构造函数体(或初始化程序)中使用动态分派。你的对象没有完全构建。
  • 异常地,您也可以尝试将其类型转换为构造函数的子类。