从具有非虚拟父级的虚拟类继承的正确方法

Posted

技术标签:

【中文标题】从具有非虚拟父级的虚拟类继承的正确方法【英文标题】:Correct way to inherit from a virtual class with non-virtual parent 【发布时间】:2012-02-04 20:33:49 【问题描述】:

我编写了这个使用三种类型的测试代码:struct One 是没有虚成员的普通类型,struct Two : One 有一个纯虚函数和一个虚析构函数,struct Three : Two 实现了Two 的界面。

#include <iostream>

struct One

    ~One() 
        std::cout << "~One()\n";
    
;

struct Two : One

    virtual ~Two() 
        std::cout << "~Two()\n";
    

    virtual void test() = 0;
;

struct Three : Two

    virtual ~Three() 
        std::cout << "~Three()\n";
    

    virtual void test() 
        std::cout << "Three::test()\n";
    
;

int main()

    Two* two = new Three;
    two->test();

    One* one = two;
    delete one;

不出所料,the output was 这个:

三::test() 〜一个()

除了将每个析构函数设为虚拟之外,还有其他方法可以解决此问题吗?还是程序员应该小心不要遇到这种情况?我觉得编译时没有警告很奇怪。

【问题讨论】:

一个简单的解决方法:使用来自 One 的私有或受保护继承,并通过使用声明公开功能。 【参考方案1】:

你必须小心,将 One 的析构函数设为虚拟。一些编译器会对此发出警告。

【讨论】:

【参考方案2】:

唯一的“修复”是不通过指向One 的指针删除对象。

这是否是常见问题取决于您的类的使用方式。例如,标准库包含像 unary_function 这样没有虚拟析构函数的结构,但我们很少看到它被这样滥用。

【讨论】:

为了强制执行,One 的析构函数应该受到保护【参考方案3】:

如果你想在派生类中使用析构函数,那么你必须将它们定义为虚拟的。这是唯一的方法。

【讨论】:

【参考方案4】:

delete one 调用未定义的行为,因为对象的动态类型与静态类型不匹配,并且静态类型没有虚拟析构函数。

避免此类问题的通常方法是使析构函数成为公共和虚拟的,或受保护的和非虚拟的(在预期以这种方式使用的类上)。

【讨论】:

以上是关于从具有非虚拟父级的虚拟类继承的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

C++中的继承和纯虚函数

当涉及部分虚拟继承时,这是计算创建的基类对象数量的正确方法吗?

Django:从带有元的抽象类的多重继承

具有抽象中间类的虚拟继承

调用非虚拟基方法时,C++ 中的虚拟继承是不是有任何惩罚/成本?

非 Diamond 类型中的虚拟继承