C++-在有些地方看到C++中的构造函数可以调用虚函数

发布于 2016-12-03 02:17:36 字数 47 浏览 1426 评论 5

但是感觉这时对象尚未构造完成,如何确定所调用的对象是哪一个呢?调用机制是怎样的?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夜无邪 2017-10-19 07:20:20

由于构造顺序的原因,构造函数调用的是本类的函数,不会调用派生类的。因为在派生类的构造函数中会先调用基类的构造函数,而派生类还没有构造,假设派生类的虚函数访问了派生类独有的成员。那么基类的构造函数如果调用的是派生类的虚函数结果是未知的,因为派生类的的成员还没有初始化。所以c++标准规定,构造函数中调用的虚函数是本类的函数~。

甜柠檬 2017-08-23 08:16:40

调用虚函数可能可以通过编译运行,但是无法实现多态性。

强烈建议在C++中不要在构造函数中调用虚函数。

参考资料:

Never Call Virtual Functions during Construction or Destruction

偏爱自由 2016-12-28 12:48:33

看看下面这段代码就知道了:

class Base
{
public:
Base()
{
Fuction();
}

virtual void Fuction()
{
cout << "Base::Fuction" << endl;
}
};

class A : public Base
{
public:
A()
{
Fuction();
}

virtual void Fuction()
{
cout << "A::Fuction" << endl;
}
};

// 这样定义一个A的对象,会输出什么?
A a;

有人说会输出:

A::Fuction
A::Fuction

如果是这样,首先我们回顾下C++对象模型里面的构造顺序,在构造一个子类对象的时候,首先会构造它的基类,如果有多层继承关系,实际上会从最顶层的基类逐层往下构造(虚继承、多重继承这里不讨论),如果是按照上面的情形进行输出的话,那就是说在构造Base的时候,也就是在Base的构造函数中调用Fuction的时候,调用了子类A的Fuction,而实际上A还没有开始构造,这样函数的行为就是完全不可预测的,因此显然不是这样,实际的输出结果是:

 Base::Fuction
A::Fuction

清晨说ぺ晚安 2016-12-25 02:20:01

在构造函数中调用析构函数是可行的(编译通过)

this->~AAA()

后果就是这个对象未构造完成就被析构掉了,这样的写法除了出题坑学生之外,毫无任何意义

想挽留 2016-12-04 02:39:29

对于在构造函数中调用一个虚函数的情况,被调用的只是这个函数的本地版本。也就是说,虚机制在构造函数中不起作用。
If you call a virtual function inside a constructor, only the local version of the function is used. That is, the virtual mechanism doesn’t work within the constructor.
--参考阅读:《C++编程思想第1卷》15.10节

这种行为有两个理由。在概念上,构造函数的工作是生成一个对象。在任何构造函数中,可能只是部分形成对象--我们只能知道基类已被初始化,但并不能知道哪个类是从这个基类继承来的。然而,虚函数在继承层次上是“向前”和“向外”进行调用。它可以调用在派生类中的函数。如果我们在构造函数中也这样做,那么我们所调用的函数可能操作还没有被初始化的成员,这将导致灾难的发生。

第二个理由是机械的。当一个构造函数被调用时,它做的首要的事情之一就是初始化它的VPTR。然而,它只能知道它属于“当前”类--即构造函数所在的类。于是它完全忽视这个时象是否是基于其他类的。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码--既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。所以它使用的VPTR必须是对于这个类的VTABLE。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR将保持被初始化为指向这个VTABLE。但如果接着还有一个更晚派生的构造函数被调用,那么这个构造函数义将设置VPTR指向它的VTABLE,以此类推,直到最后的构造函数结束。VPTR的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是按照从基类到最晚派生的类的顺序的另一个理由。

但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置VPTR指向它自己的VTABLE。如果函数调用使用虚机制,它将只产生通过它自己的VTABLE的调用,而不是最后派生的VTABLE(所有构造函数被调用后才会有最后派生的VTABLE)。另外,许多编译器认识到,如果在构造函数中进行虚函数调用,应该使用早捆绑,因为它们知道晚捆绑将只对本地函数产生调用。无论哪种情况,在构造函数中调用虚函数都不能得到预期的结果。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文