1

{ 使用 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可以防止这种崩溃。我想我部分明白了为什么。破坏与构造的顺序相反,因此首先执行 d'tor ,并且在调用 d'tor 之前破坏Derived的所有功能。同时,如果遇到应用程序将崩溃。它崩溃说纯虚拟调用。我无法理解这部分。有人可以解释一下吗?DerivedBasepThis->vfunc()

4

2 回答 2

5

您的基类析构函数需要virtual,因为它不是此代码调用未定义行为

参考:
C++03 标准:第 5.3.5/3 节:

如果操作数的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类,且静态类型应具有虚拟析构函数或行为未定义。


当您通过构造函数/析构函数调用虚函数时,动态调度不会像您期望的那样工作。
in 构造函数/析构函数的类型this是正在执行构造函数/析构函数的类的类型。虽然您希望动态调度调用覆盖的派生类方法Derived::vfunc(),但它最终会调用Base::vfunc()没有定义的调用,因此会导致未定义的行为

参考:
C++03 标准 10.4/6:

“可以从抽象类的构造函数(或析构函数)调用成员函数;直接或间接对从此类构造函数创建(或销毁)的对象进行虚拟调用(10.3)的效​​果(或析构函数)未定义。”

于 2012-10-03T06:43:14.130 回答
2

发生这种情况是因为您的代码vfunc可以在Base::Base()尚未完成或Base::~Base()已经开始时调用。这两种情况都会调用未定义的行为,通常表现为“纯虚调用”错误。出现错误的原因是“虚拟”机制直到大多数派生对象的类的构造函数开始运行后才会生效,而“虚拟”机制在大多数派生对象的类的析构函数完成后才生效跑步。因此,当您在对象上执行构造函数或析构函数时调用虚函数时,将调用构造函数或析构函数正在执行的类的相应函数。如果该函数恰好是纯虚函数,则行为未定义。

ISO/IEC 14882:2003, 10.4/6: 可以从抽象类的构造函数(或析构函数)调用成员函数;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚调用(10.3)的效​​果是未定义的。

于 2012-10-03T06:47:32.543 回答