可能的重复:
在构造函数中调用虚函数 https://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors
看看这段代码。
在基类的构造函数中,我们可以使用“this”指针来调用纯虚函数。现在,当我想创建一个指向同一类的类型化指针并将“this”转换为同一类型时。它抛出运行时异常“纯虚函数调用异常”。为什么会这样呢?
#include <iostream>
using namespace std;
class Base
{
private:
virtual void foo() = 0;
public:
Base()
{
//Uncomment below 2 lines and it doesn't work (run time exception)
//Base * bptr = (Base*)this;
//bptr->foo();
//This call works
this->foo();
}
};
void
Base::foo()
{
cout << "Base::foo()=0" << endl;
}
class Der : public Base
{
public:
Der()
{
}
public:
void foo()
{
cout << "Der::foo()" << endl;
}
};
int main()
{
cout << "Hello World!" << endl;
Der d;
}
你必须永远不要在构造函数中调用虚函数.
虚拟函数不会按照您想象的方式进行调度。相反,在施工过程中,dynamic正在构造的基子对象的类型是基类型,因此该函数被分派给基函数(在您的情况下是纯虚拟的)。
只是不要这样做。
(原因很明显:在构造派生对象时,必须首先构造基础子对象,因此环境派生对象在基础构造时甚至不存在。)
编辑:这里有一些更多的解释。完全允许并鼓励编译器执行虚拟调度静态地如果他们能做到的话。在这种情况下,在编译时就已经确定将调用哪个实际函数。当你说时会发生这种情况foo()
or this->foo()
in the Base
构造函数,或者当你说x.Base::foo()
在其他一些情况下Derived x;
是你的对象。当调度静态发生时,那么要么执行Base::foo()
直接调用,或者如果没有实现,您会收到链接器错误。
另一方面,如果调度发生动态地,即在运行时,则有可能(尽管不寻常)调度实际上最终选择了Base::foo()
作为最终目标。这在“正常”条件下不会发生,因为编译器不会让你用纯虚函数实例化一个类,因此普通动态调度的目标始终是一个必须存在实现的函数(或者至少你如果您不链接它,则会收到链接器错误)。
但还有一种情况,也就是我们所讨论的情况:无论出于何种原因,编译器决定在运行时执行分派,并且 dipatch 以纯虚函数结束。在这种情况下,您的程序将终止。该函数是否实现并不重要,但它只是在多态类层次结构中没有条目(将其视为“vtable 中的空指针”,因此= 0
)。为了实现这一点,dynamic对象的类型必须是抽象基类的类型,and调度必须动态发生。前者只能在派生对象的基本构造函数内实现,后者需要您说服编译器不要静态分派调用。这就是两者的区别所在this->foo()
(静态)和Base * p = this; p->foo();
(动态)出现。(也将其与x.Base::foo()
,已发送静态地.)
当然,所有这一切仅仅是实施的结果,并被“未定义的行为”所涵盖。如果你想从中去掉一件事,那就是动态调度找不到纯虚函数。当然,您绝不能在构造函数中调用虚函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)