可更新接口中的虚拟析构函数可以吗?

are virtual destructors in novtable interfaces okay?

本文关键字:析构函数 虚拟 接口 可更新      更新时间:2023-10-16

我有一个Visual Studio 2008 C++03项目,其中我有一个声明为_declspec( novtable )的接口类。例如:

class _declspec( novtable ) IFoo
{
public:
    virtual void FooDo() const = 0;
};
class Foo : public IFoo
{
public:
    ~Foo() { printf( "~Foo()rn" ); };
    void FooDo() const { printf( "FooDo()rn" ); };
};
int main( int argc, char* argv[] )
{
    IFoo* foo = new Foo();
    foo->FooDo();
    delete foo;
    return 0;
}

由于IFoo没有虚拟析构函数,因此永远不会调用具体的Foo析构函数。

输出:

FooDo()

期望输出:

FooDo()
~Foo()

但是,在 MSDN 中,有一个可怕的警告,不要在声明为 novtable 的接口类中调用函数。"如果您尝试实例化标记为 novtable 的类,然后访问类成员,您将收到访问冲突 (AV)。因此,添加virtual ~IFoo() { };成员听起来可能是一件坏事。(尽管在我的测试中,它似乎工作正常。

如何从中正确获得所需的行为?

接口类中包含虚拟析构函数应该没问题。您已经包含另一个虚拟方法并调用了它,因此析构函数应该没有什么不同。

novtable的效果是IFoo的 vtable 不会被初始化。不过没关系,因为您从不直接实例化IFoo。相反,您可以实例化该类的后代。后代有一个 vtable,并且该 vtable 使用指向Foo方法的指针正确初始化(和IFoo,如果IFoo有任何Foo不覆盖的非纯虚拟方法)。从 Foo 内部调用~IFoo是非虚拟调度,因此仍然不需要 IFoo 的 vtable。