将基类指针分配给在免费商店中创建的派生类对象

时间:2013-07-17 13:35:45

标签: c++ virtual new-operator

我正在尝试使用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中尝试了代码

2 个答案:

答案 0 :(得分:1)

您正在两个地方进入未定义行为的奇妙世界:

delete pb1;
delete pb2;

这是未定义的行为,因为niether Base1Base2都有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)

通过指向基类型的指针删除派生类型的对象时,基类型必须具有虚拟析构函数。没有它你就有未定义的行为。因此:向Base1Base2添加虚拟析构函数。