使用构造函数创建对象,以及正在构造的对象的调用函数:
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
答案 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
来支持初始化列表。