3

我有一个 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()\r\n" ); };
    void FooDo() const { printf( "FooDo()\r\n" ); };
};

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() { };成员听起来可能是一件坏事。(虽然在我的测试中,它似乎工作正常。)

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

4

1 回答 1

6

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

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

于 2012-05-17T17:46:16.523 回答