我正在尝试c++,试图了解继承并编写了以下代码:

#include <iostream>
#include <cstdlib>

class Base1{
public:
    virtual void print_hello() const
    { std::cout << "Base1: Hello!" << std::endl;}
};

class Base2{
public:
    virtual void print_hello() const
    { std::cout << "Base2: Hello!" << std::endl; }
};

class Derived: public Base1, public Base2
{
public:
    virtual void print_hello() const
    { std::cout << "Derived: Hello!" << std::endl; }
};

int main() {
Base1* pb1=new Derived;

pb1->print_hello();

delete pb1;

Base2* pb2=new Derived;

pb2->print_hello();

delete pb2;

return EXIT_SUCCESS;}

代码编译正常,但是当我运行它时,出现运行时错误:
Derived: Hello!
Derived: Hello!
*** glibc detected *** ./a.out: free(): invalid pointer: 0x0000000001b0c018 ***

然后是返回跟踪和内存映射列表

屏幕上都打印了两个cout语句,所以我想尝试删除pb2时会导致错误。

如果我未将成员函数指定为虚拟,则代码运行正常。如果我在删除pb1(即pb1=new Derived;)之后重用了pb1,而不是创建新的指针pb2,则代码也可以正常运行。我在这里想念什么?

PS:我在Ubuntu 12.04中尝试了同时使用g++(4.6.4)和icc(2013.3.163)的代码

最佳答案

您将在两个地方进入“ undefined 行为”的奇妙世界:

delete pb1;
delete pb2;

这是 undefined 的行为,因为同时Base1Base2都具有virtual析构函数,但是您尝试对通过基本指针指向的对象进行delete

您可能会惊讶于第一个实例(delete pb1)也是 undefined 行为,因为它似乎可以工作。这就是 undefined 行为的美丽-可能发生任何事情,甚至是您期望发生的事情。

通常,使用多态时,您的基类应始终具有virtual析构函数。在许多情况下,这可能是微不足道的:
class Base1{
public:
    virtual void print_hello() const
    { std::cout << "Base1: Hello!" << std::endl;}
      virtual ~Base1() {}
};

class Base2{
public:
    virtual void print_hello() const
    { std::cout << "Base2: Hello!" << std::endl; }
      virtual ~Base2() {};
};

我还要指出,您的层次结构有些...不寻常。通常不需要多重继承。通常,有更好的方法可以完成您想做的事情。当您使用多重继承时,拥有多个具有相同名称的成员函数的基类几乎总是一个设计缺陷。通常,您将获得意外(但定义明确)的行为。

10-06 04:08