我正在尝试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 的行为,因为同时
Base1
和Base2
都具有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() {};
};
我还要指出,您的层次结构有些...不寻常。通常不需要多重继承。通常,有更好的方法可以完成您想做的事情。当您使用多重继承时,拥有多个具有相同名称的成员函数的基类几乎总是一个设计缺陷。通常,您将获得意外(但定义明确)的行为。