简体   繁体   中英

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

I was experimenting with c++, trying to understand inheritance and wrote the following code:

#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;}

The code compiled ok but when I ran it, I got a run time error:

Derived: Hello!
Derived: Hello!
*** glibc detected *** ./a.out: free(): invalid pointer: 0x0000000001b0c018 ***

followed by a Back trace and a memory map list

Both cout statements were printed in the screen so I guess the error originates when trying to delete pb2.

If I do not specify the member functions virtual, the code runs ok. The code also runs ok if I reuse pb1 after I delete it (ie pb1=new Derived; ), instead of creating the new pointer pb2. What am I missing here?

PS: I tried the code in Ubuntu 12.04 using both g++ (4.6.4) and icc (2013.3.163)

You are entering in to the wonderful world of Undefined Behavior, in two places:

delete pb1;
delete pb2;

This is Undefined Behavior because niether Base1 nor Base2 have virtual destructors, but you are trying to delete the objects pointed to through a base pointer.

It might suprise you that the first instance ( delete pb1 ) is also Undefined Behavior, because it appears to work. That's the beauty of Undefined Behavior -- anything can happen, even what you were expecting to happen.

As a rule, when using polymorphism your base classes should always have a virtual destructor. In many cases, it can be trivial:

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() {};
};

I'll also point out that your hierarchy is somewhat... unusual . Generally multiple inheritence is not needed. There are usually better ways to accomplish what you're trying to do. When you do use multiple inheritence, it's almost always a design flaw to have multiple base classes that have member functions with the same name. You are generally going to get unexpected (but well-defined) behavior.

When you delete an object of a derived type through a pointer to the base type, the base type must have a virtual destructor. Without it you have undefined behavior. So: add a virtual destructor to Base1 and to Base2 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM