模板化的Pointer类可以有一个虚拟析构函数吗?

bgp*_*000 5 c++ visual-c++

当用自制的指针类实现pimpl成语时,我遇到了一个惊人的启示(我知道:为什么要自己滚动?但请耐心等待).以下三个文件包含一个最小示例:

Pointer.h:

#pragma once 

template <typename T>
class Pointer
{
public:
    Pointer(T*p=0)
        : _p(p)
    {
    }
    virtual ~Pointer()
    {
        delete _p;
    }
private:
    void operator=(const Pointer&);
    Pointer(const Pointer&);

private:
    T*_p;
};
Run Code Online (Sandbox Code Playgroud)

foo.h中:

#pragma once
#include "Pointer.h"

struct Foo
{
    Foo();
    ~Foo();

private:
    void operator=(const Foo&);
    Foo(const Foo&);

private:
    Pointer<struct FooPrivate> p;
};
Run Code Online (Sandbox Code Playgroud)

main.cpp中:

#include "Foo.h"

int main(int argc, char* argv[])
{
    Foo foo;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

别介意内脏的Foo.cpp样子.当我main.cpp使用MSVC 2008 编译时,我收到警告:

pointer.h(13) : warning C4150: deletion of pointer to incomplete type 'FooPrivate'; no destructor called
Run Code Online (Sandbox Code Playgroud)

通过从Pointers析构函数中删除关键字virtual可以避免警告.

这对我来说毫无意义.这个警告是合法的,还是MSVC编译器中的错误?如果是这样,我可以安全地忽略警告吗?

我知道在这种情况下使析构函数虚拟是没有意义的,但请记住,这只是一个最小的可编译示例.我原来的代码要复杂得多.

Den*_*ose 4

如果没有virtual,则只有一处将调用析构函数;在 之内~Foo,此时您大概已经完全定义了FooPrivate。如果在其他地方创建了另一个实例Pointer<FooPrivate>,您可能会收到警告,但由于您没有这样做,编译器可以告诉您的行为是安全的。

使用virtual,理论上您可以从 派生Pointer<FooPrivate>,并且可以从未完全定义的地方销毁该新对象FooPrivate。编译器不确定您不这样做,因此会发出警告。在这种微不足道的情况下,您可以放心地忽略它,但如果您确实需要虚拟析构函数,那么认真考虑它可能是个好主意。