C++继承测试

C++ Inheritance quiz

本文关键字:测试 继承 C++      更新时间:2023-10-16

最近有人问我一个基本的C++问题,我实际上不知道答案,也从来没有找到答案。问题是:

运行此程序时,可能会导致错误。你会对基类做什么更改来修复它?

#include <iostream>
class Base {
public:
    virtual void ShowMessage () {
        std::cout << "Base class messagen";
    }
    // Something should be added here!
};
class Derived : public Base {
public:
    explicit Derived (const std::string & value)
        : myValue(value)
    {
    }
    virtual void ShowMessage () {
        std::cout << "Derived class message " << myValue << "n";
    }
private:
    std::string myValue;
};
int main () {
    Base * obj = new Derived("Test message");
    obj->ShowMessage();
    delete obj;
}

它在我的机器上编译和运行都很好。有人知道他们在找什么吗?

您需要向基类添加一个虚拟析构函数。

class Base {
public:
    virtual void ShowMessage () {
        std::cout << "Base class messagen";
    }
    virtual ~Base() {}
};

在您的情况下,Derived::myvalue将不会正确释放。

一个虚拟析构函数。当执行此代码时。。。
delete obj;

它不会知道有一个CCD_ 1要销毁/解除分配,除非该销毁器是以多态方式调用的(即通过虚拟调度)。这是因为在没有虚拟调度的情况下,基类析构函数会运行,而且它不需要担心std::string数据成员,因此不包括与之相关的代码

指导原则很简单:无论何时使用指向基类的指针删除对象,都应该确保基类具有虚拟析构函数。

其他任何事情都存在上述问题,并且在技术上都是未定义的行为。虽然尝试对未定义的行为进行"推理"不是一个好主意,因为你不能确定发生的事情不会比预期的更糟(如果不是现在,那么在一些更高级的编译器/编译器版本上,或者使用不同的编译开关或周围的代码,另一个CPU等),在这种情况下,内存泄漏是一个明显的可能结果:std::string构造函数可以被期望动态地new生成一个字符数组,如果运行的话,指导程序会删除它。尽管如此,也可能存在其他问题——如果派生类的数据成员是共享指针,那么指向的对象可能无法正确地进行销毁/释放,如果存在文件句柄、共享内存句柄、线程、锁等,则无法调用销毁器的后果可能会很严重:数据可能无法被清除到预期目的地,应用程序可能会在多次泄漏后耗尽资源,或者稍后当其他代码试图获取它仍然持有的锁时,它可能会挂起。。。。

您必须使析构函数为虚拟的,因为删除没有虚拟析构函数的多态类型会导致未定义的行为:

根据5.3.5.3:

在第一个备选方案(删除对象)中,如果要删除的对象与其动态类型、静态类型不同type应为待处理对象的动态类型的基类已删除且静态类型应具有虚拟析构函数或行为未定义。在第二个备选方案(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,行为是未定义的。