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.