0

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

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

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

     virtual void DoStuff() {};
}

...

ITestInferface *pThing = new Test();
delete *pThing; // undefined

通常,您要么为基类定义一个虚拟析构函数,要么将其声明为私有以防止在接口指针上调用 delete。

如果您声明没有 vtable 的接口

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

现在通过接口指针删除对象是明确定义的行为,并调用适当的析构函数吗?我不明白为什么会这样,但被告知不是这样。

4

1 回答 1

2

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

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

于 2020-08-06T01:09:46.757 回答