{使用Visual Studio 2010,Win7}
class Base
{
public:
Base() : terminateCondition(false)
{
//spawn new thread and set entry point to newThreadFunc()
}
virtual ~Base() // edited to say it's virtual.
{
terminateCondition=true;
//wait for thread to join
}
virtual void vfunc() = 0;
static void __stdcall newThreadFunc(void *args)
{
while(!terminateCondition)
pThis->vfunc();
}
volatile bool terminateCondition;
};
class Derived : public Base
{
public:
virtual void vfunc()
{
//Do Something
}
};
Derived* dPtr=new Derived; //now assume pThis is dptr
//later somewhere
delete dPtr;
此代码崩溃说pure virtual called
。将terminateCondition=true
移动到Derived
的析构函数可以防止此崩溃。我想我部分理解为什么。破坏与构造的顺序相反,因此Derived
的执行首先执行,Derived
的所有功能都被销毁,然后再调用Base
。在此期间,如果遇到pThis->vfunc()
,应用程序将崩溃。它崩溃说纯虚拟叫。我无法理解这一部分。有人可以解释一下吗?
答案 0 :(得分:4)
您的基类析构函数必须为virtual
,因为不是此代码调用未定义行为。
参考:
C ++ 03标准:第5.3.5 / 3节:
如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义。
当你通过构造函数/析构函数调用虚函数时,动态调度不会像你期望的那样工作。
构造函数/析构函数中this
的类型是正在执行构造函数/析构函数的类的类型。虽然您希望动态调度调用覆盖的派生类方法Derived::vfunc()
,但它最终会调用Base::vfunc()
而没有定义,从而导致未定义行为。
参考:
C ++ 03标准10.4 / 6:
“可以从抽象类的构造函数(或析构函数)调用成员函数;对于正在创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用(10.3)的效果构造函数(或析构函数)未定义。“
答案 1 :(得分:2)
发生这种情况是因为代码vfunc
可以在Base::Base()
尚未完成或Base::~Base()
已启动时调用。这两种情况都会调用未定义的行为,通常表现为“纯虚拟调用”错误。
它是一个错误的原因是,在大多数派生对象的类的构造函数开始运行之后,“虚拟”机制才会启动,并且在大多数派生对象的类的析构函数完成后,“虚拟”机制不再生效运行。因此,当在对象上执行构造函数或析构函数时调用虚函数时,将调用构造函数或析构函数正在执行的类的相应函数。如果该函数恰好是纯虚函数,则行为未定义。
ISO / IEC 14882:2003,10.4 / 6: 可以从抽象类的构造函数(或析构函数)调用成员函数;制作的效果 虚拟调用(10.3)直接或间接为正在创建的对象的纯虚函数(或
。来自这样的构造函数(或析构函数)是未定义的