我正在尝试使用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 ***
后跟Back跟踪和内存映射列表
两个cout语句都打印在屏幕上,所以我猜想在尝试删除pb2时会出现错误。
如果我没有指定成员函数virtual,则代码运行正常。如果我在删除pb1之后重新使用pb1(即pb1=new Derived;
),而不是创建新的指针pb2,那么代码也运行正常。我在这里缺少什么?
PS:我使用g ++(4.6.4)和icc(2013.3.163)在Ubuntu 12.04中尝试了代码
答案 0 :(得分:1)
您正在两个地方进入未定义行为的奇妙世界:
delete pb1;
delete pb2;
这是未定义的行为,因为niether Base1
和Base2
都有virtual
析构函数,但是你试图delete
通过基指针指向的对象。
第一个实例(delete pb1
)也是未定义的行为可能会让您感到惊讶,因为它似乎有效。这就是未定义行为之美 - 任何都可能发生,即使是你期望发生的事情。
通常,在使用多态时,基类应始终具有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() {};
};
我还会指出你的等级有点...... 不寻常。通常不需要多重继承。通常有更好的方法来完成你想要做的事情。当你使用多重继承时,拥有多个具有相同名称的成员函数的基类几乎总是一个设计缺陷。您通常会遇到意外(但定义明确)的行为。
答案 1 :(得分:0)
通过指向基类型的指针删除派生类型的对象时,基类型必须具有虚拟析构函数。没有它你就有未定义的行为。因此:向Base1
和Base2
添加虚拟析构函数。