将基类指针分配给在自由存储中创建的派生类对象

assigning a base class pointer to a derived class object created in the free store

本文关键字:创建 派生 对象 存储 自由 指针 基类 分配      更新时间:2023-10-16

我在试验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时产生的。

如果我没有指定成员函数virtual,代码运行ok。如果我在删除pb1(即pb1=new Derived;)后重用它,而不是创建新的指针pb2,代码也运行ok。我在这里错过了什么?

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

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

delete pb1;
delete pb2;

这是"未定义的行为",因为Base1Base2都没有virtual析构函数,但您正试图delete通过基指针指向的对象。

第一个实例(delete pb1)也是Undefined Behavior,这可能会让您感到惊讶,因为它似乎可以工作。这就是未定义行为的美妙之处——任何的事情都可能发生,即使是你期望发生的事情。

通常,当使用多态性时,基类应该始终具有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() {};
};

我还要指出,你的等级制度在某种程度上异常。通常不需要多重继承。通常有更好的方法来完成你想要做的事情。当你使用多个继承时,拥有多个具有相同名称的成员函数的基类几乎总是一个设计缺陷。你通常会得到意想不到的(但定义明确的)行为。

通过指向基类型的指针删除派生类型的对象时,该基类型必须具有虚拟析构函数。没有它,你就会有不明确的行为。所以:向Base1Base2添加一个虚拟析构函数。