在没有虚拟析构函数的情况下在 novtable 基 class 上删除的行为
Behaviour of delete on novtable base class without a virtual destructor
据我了解,如果您在接口指针(或更具体地说是基 class 指针,指向派生 class 实例)上调用 delete,并且该声明没有虚拟析构函数,则结果行为未定义,派生对象的析构函数不会被调用。
class ITestInterface
{
public:
virtual void DoStuff() = 0;
}
class Test : public ITestInterface
{
public:
~Test(){};
virtual void DoStuff() {};
}
...
ITestInferface *pThing = new Test();
delete *pThing; // undefined
通常,您要么为基 class 定义一个虚拟析构函数,要么将其声明为私有以防止在接口指针上调用 delete。
如果你声明的接口没有 vtable
class __declspec(novtable) ITestInterface
{
public:
virtual void DoStuff() = 0;
}
现在通过接口指针删除对象是否是定义明确的行为,并调用适当的析构函数?我不明白为什么会这样,但有人告诉我不是这样。
__declspec(novtable)
的作用是在class的构造函数和析构函数中省略了vtable指针的初始化。由于用于纯虚拟接口的 vtable 基本上无用,因此这是一种 code-size-reduction 技术。它只会影响构造函数中虚函数的可用性,所以只要您不在构造函数中进行需要虚拟分派的调用(无论如何都是 bad idea),一切都很好。
但是,关于此属性的任何内容都没有说明它在未声明时神奇地调用了基类型析构函数 virtual。仅根据文档,如果没有 explicitly-declared(或继承的)虚拟析构函数,通过指向接口的指针删除对象仍然是未定义的行为。
据我了解,如果您在接口指针(或更具体地说是基 class 指针,指向派生 class 实例)上调用 delete,并且该声明没有虚拟析构函数,则结果行为未定义,派生对象的析构函数不会被调用。
class ITestInterface
{
public:
virtual void DoStuff() = 0;
}
class Test : public ITestInterface
{
public:
~Test(){};
virtual void DoStuff() {};
}
...
ITestInferface *pThing = new Test();
delete *pThing; // undefined
通常,您要么为基 class 定义一个虚拟析构函数,要么将其声明为私有以防止在接口指针上调用 delete。
如果你声明的接口没有 vtable
class __declspec(novtable) ITestInterface
{
public:
virtual void DoStuff() = 0;
}
现在通过接口指针删除对象是否是定义明确的行为,并调用适当的析构函数?我不明白为什么会这样,但有人告诉我不是这样。
__declspec(novtable)
的作用是在class的构造函数和析构函数中省略了vtable指针的初始化。由于用于纯虚拟接口的 vtable 基本上无用,因此这是一种 code-size-reduction 技术。它只会影响构造函数中虚函数的可用性,所以只要您不在构造函数中进行需要虚拟分派的调用(无论如何都是 bad idea),一切都很好。
但是,关于此属性的任何内容都没有说明它在未声明时神奇地调用了基类型析构函数 virtual。仅根据文档,如果没有 explicitly-declared(或继承的)虚拟析构函数,通过指向接口的指针删除对象仍然是未定义的行为。