【问题标题】:Destructor in virtual inheritance虚拟继承中的析构函数
【发布时间】:2016-08-14 03:14:33
【问题描述】:
class Base{};
class D1:virtual public Base{};
class D2:virtual public Base{};
class DD:public D1,public D2{};

int main(){
    Base *pBase=new DD;
    delete pBase;
}

这会导致崩溃,但我修改如下:

class Base{
public:
    virtual ~Base(){};
};

class D1:virtual public Base{
public:
    virtual ~D1(){}
};

class D2:virtual public Base{
public:
    virtual ~D2(){}
};

class DD:public D1,public D2{
};

然后,它通过了,但是默认的析构函数应该是虚拟的哑函数,不是吗?

【问题讨论】:

  • 请不要使用 Microsoft _tmain 发布代码,除非它是 Visual C++ 特定的代码。它使其他人更难尝试您的代码,并教新手不良习惯。为你解决了这个问题。只需使用标准的int main()
  • virtual 在声明中做了什么:class D : virtual public Base?我从未见过这种结构(这可能是我的无知......)。
  • @Chiel en.wikipedia.org/wiki/Virtual_inheritance,当你继承多个共享同一个基类的类时使用它。
  • 隐式声明的析构函数不是虚拟的。
  • 尽管如此,您的代码在 clangg++ 中都可以正常编译,并且在这里也不会崩溃。

标签: c++ destructor delete-operator virtual-inheritance virtual-destructor


【解决方案1】:

来自 C++11 规范 (ISO/IEC 14882:2011(E)),第 12.4 节析构函数 [class.dtor]:

第 4 小节:

如果一个类没有用户声明的析构函数,则析构函数被隐式声明为默认值 (8.4)。隐式声明的析构函数是其类的内联公共成员。

第 6 小节:

默认且未定义为已删除的析构函数在被 odr 使用 (3.2) 销毁其类类型 (3.7) 的对象时或在其第一次声明后显式默认时被隐式定义。

最后是第 9 小节:

析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果一个类有一个带有虚拟析构函数的基类,那么它的析构函数(无论是用户声明的还是隐式声明的)都是虚拟的。

在最后一句强调我的。

编译器将生成一个虚拟析构函数如果基类有一个虚拟析构函数。如果基类没有虚拟析构函数,例如第一个示例中的Base,那么子类将没有虚拟析构函数。如果一个类没有基类,编译器生成的析构函数将不是虚拟的。

【讨论】:

    【解决方案2】:

    这与虚拟继承无关。

    通过指向类型 T 而非最初分配的类型 D 的指针删除是未定义行为,除非类型 T 是 D 的基类并且具有虚拟析构函数。

    C++14(如 N3936 草案)§5.3.5/3

    ...如果要删除的对象的静态类型与其不同 动态类型,静态类型应该是要删除的对象的动态类型的基类, 静态类型应具有虚拟析构函数,否则行为未定义。

    虚拟析构函数用于识别类型 D,特别是它的大小和析构函数,可能还有它的自定义释放函数(您的代码没有那个)。


    回复

    默认的析构函数应该是virtual dummy function,不是吗?

    不,不是。

    因为 C++ 设计的一个指导原则是不用为不使用的东西付费,而另一个指导原则是让程序员控制自己,让程序员能够表达任何需要(例如,出于某种目的)内存中的二进制布局)。

    仅当基类具有虚拟析构函数时,您才会获得默认的虚拟析构函数。

    【讨论】:

      猜你喜欢
      • 2011-01-12
      • 1970-01-01
      • 2015-06-21
      • 2020-03-10
      • 2012-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多