在派生指针上显式调用基类析构函数时编译错误

Compile error when explicitly calling the base class destructor on a derived pointer

本文关键字:析构函数 基类 编译 错误 调用 派生 指针      更新时间:2023-10-16

就像标题所说的那样。下面的人为示例似乎可以在codepad: http://codepad.org/4cgGmvDQ和我的Linux机器上的GCC 4.1.2下工作。

#include<stdlib.h>
#include<new>
class IBase
{
public:
    virtual ~IBase(){}
};
class B : public IBase
{
public:
    virtual ~B(){}
};
class D : public B
{
public:
    virtual ~D(){ }
};
int main()
{
    void* p = malloc(sizeof(D));
    D* d = new(p) D();
    B* b = static_cast<B*>(d);
    b->~IBase();
    free(p);
}

但是Visual Studio Pro 2012 11.0.61030.00 Update 4失败了:

main.cpp(30): error C2300: 'B' : class does not have a destructor called '~IBase'

显然,这个例子可以很容易地重新设计以避免这个问题,但我的实际代码库并没有给我任何其他选择。有人知道微软编译器的这个特殊缺陷吗?

这不是MSVC中的错误。出自标准§3.4.5 [basic.lookup]。/p2-3(引用N3936,重点是我的):

如果类成员访问(5.2.5)中的id-表达式 unqualified-id , [...]

如果unqualified-id~type-name,则查找类型名称在整个后缀表达式的上下文中。如果类型为T对象表达式的类类型为C,类型名为在C类的范围内查找。至少一个查找应该找到一个指向(可能是cv-qualified) T的名称。

在您的代码中,TB,而查找IBase显然找不到指向B的名称。因此,您的代码是病态的。如果g++接受它,它要么是一个bug,要么是一个扩展。

因为听起来B代表的实际类型在您的实际代码中是"不可说的",但IBase可以编写,最简单的解决方案是简单地将b转换为IBase *

这是一个已知的bug。至于"为什么"它失败了,我没有答案。您的示例的解决方法可能是:

b -> IBase:: ~ IBase ();

自动调用基类析构函数。如果你手动调用基类析构函数,那么当对象被析构时,它将被第二次调用。