4

我编写了这个使用三种类型的测试代码: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()
~One()

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

4

4 回答 4

2

唯一的“修复”是不通过指向One.

如果这是一个常见的问题,或者不是,取决于你的类是如何使用的。例如,标准库包含unary_function没有虚拟析构函数的结构,但我们很少看到它被这样滥用。

于 2012-01-07T11:30:46.183 回答
2

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

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

于 2012-01-07T11:37:20.613 回答
1

您必须小心并让 One 的析构函数变为虚拟。一些编译器确实对此提出警告。

于 2012-01-07T11:26:52.427 回答
1

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

于 2012-01-07T11:32:19.620 回答