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

发布于 2024-12-25 10:28:15 字数 892 浏览 5 评论 0原文

我编写了使用三种类型的测试代码: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;
}

毫不奇怪,输出是

三::test()
〜一()

除了使每个析构函数都是虚拟的之外,还有什么方法可以解决这个问题吗?或者程序员应该小心不要遇到这种情况吗?我觉得奇怪的是编译时没有任何警告。

I've written this test code that uses three types: struct One is a normal type with no virtual members, struct Two : One has a pure virtual function and a virtual destructor, and struct Three : Two implements Two's interface.

#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;
}

Unsurprisingly, the output was this:

Three::test()
~One()

Is there any way to fix this other than making every destructor virtual? Or should programmers just be careful not to run into this situation? I find it odd that there's no warning when compiling this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不忘初心 2025-01-01 10:28:15

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

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

The only "fix" is not to delete the objects through a pointer to One.

If this is a frequent problem, or not, depends on how your classes are used. For example, the standard library contains structs like unary_function without a virtual destructor, but we hardly ever see it misused like this.

私野 2025-01-01 10:28:15

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

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

delete one invokes undefined behaviour, because the dynamic type of the object does not match the static type, and the static type does not have a virtual destructor.

The usual way to avoid problems like this is to make destructors be either public and virtual, or protected and non-virtual (on classes that are expected to be used in this way).

坏尐絯 2025-01-01 10:28:15

你必须小心并把 One 的析构函数设为虚拟。一些编译器确实对此发出警告。

You must be careful and make One's destructor virtual. Some compilers do warn about this.

诠释孤独 2025-01-01 10:28:15

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

If you want working destructors in derived classes then you must define them as virtual. It is the only way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文