C++ 无虚拟析构函数的novtable基类上的delete行为

C++ 无虚拟析构函数的novtable基类上的delete行为,c++,visual-c++,declspec,C++,Visual C++,Declspec,据我所知,如果对接口指针(或者更具体地说是指向派生类实例的基类指针)调用delete,并且该声明没有虚拟析构函数,那么结果行为是未定义的,并且派生对象的析构函数不会被调用 class ITestInterface { public: virtual void DoStuff() = 0; } class Test : public ITestInterface { public: ~Test(){}; virtual void DoStuff() {};

据我所知,如果对接口指针(或者更具体地说是指向派生类实例的基类指针)调用delete,并且该声明没有虚拟析构函数,那么结果行为是未定义的,并且派生对象的析构函数不会被调用

class ITestInterface
{
  public:
    virtual void DoStuff() = 0;
}

class Test : public ITestInterface
{
  public:
     ~Test(){};

     virtual void DoStuff() {};
}

...

ITestInferface *pThing = new Test();
delete *pThing; // undefined
通常,可以为基类定义虚拟析构函数,也可以将其声明为private以防止在接口指针上调用delete

如果您声明的接口没有vtable

class __declspec(novtable) ITestInterface
{
  public:
    virtual void DoStuff() = 0;
}


通过接口指针删除对象现在是否是定义良好的行为,并调用相应的析构函数?我不明白为什么会这样,但有人告诉我不是这样。

declspec(novtable)的效果是在类的构造函数和析构函数中省略vtable指针的初始化。由于纯虚拟接口的vtable基本上是无用的,因此这是一种减少代码大小的技术。它只会影响构造函数中虚拟函数的可用性,因此只要您不在构造函数中进行需要虚拟分派的调用(这无论如何都是一个问题),一切都很好


但是,这个属性并没有说明它在未声明时神奇地调用了基类型析构函数virtual。仅根据文档,如果没有显式声明(或继承)的虚拟析构函数,通过指向接口的指针删除对象仍然是未定义的行为。

declspec(novtable)的效果是在类的构造函数和析构函数中忽略vtable指针的初始化。由于纯虚拟接口的vtable基本上是无用的,因此这是一种减少代码大小的技术。它只会影响构造函数中虚拟函数的可用性,因此只要您不在构造函数中进行需要虚拟分派的调用(这无论如何都是一个问题),一切都很好


但是,这个属性并没有说明它在未声明时神奇地调用了基类型析构函数virtual。仅根据文档,如果没有显式声明(或继承)的虚拟析构函数,通过指向接口的指针删除对象仍然是未定义的行为。

简单地声明它novtable并不能解决删除时无法分派到派生类的析构函数的问题,是吗?如果接口没有虚拟析构函数,则通过接口指针删除不会查找派生类的析构函数。@Kindread我显然没有正确处理问题的这一部分。让我来编辑。谢谢!我是否应该以某种方式澄清我的问题,以便让未来读者更清楚地了解你遇到的问题?@Kindread不,你的问题完全可以。我在阅读问题时分心了,没有抓住非虚拟析构函数的重要细节,而是专注于novtable部分。简单地声明novtable并不能解决删除时无法分派到派生类的析构函数的问题,不是吗?如果接口没有虚拟析构函数,则通过接口指针删除不会查找派生类的析构函数。@Kindread我显然没有正确处理问题的这一部分。让我来编辑。谢谢!我是否应该以某种方式澄清我的问题,以便让未来读者更清楚地了解你遇到的问题?@Kindread不,你的问题完全可以。我在阅读问题时分心了,没有抓住非虚拟析构函数的重要细节,而是专注于novtable部分。