user686740
user686740

Reputation: 33

c++ inheritance

I was playing around with some of c++ futures, and got into something that does intrigue me.

class Base
{
       public:
          Base(){ cout<<"C: Base"<<endl;}
          ~Base(){ cout<<"D : Base"<<endl;}
};
class Derived: public Base
{
       public:
           Derived(){ cout<<"C: Derived"<<endl;}        
           ~Derived(){ cout<<"D : Derived"<<endl;}
};

class Derived2: public Derived
{
       public:
           Derived2(){ cout<<"C: Derived2"<<endl;}
           ~Derived2(){ cout<<"D : Derived2"<<endl;}
};

class Derived3: public Derived2
{
       public:
           Derived3(){ cout<<"C: Derived3"<<endl;}
           ~Derived3(){ cout<<"D : Derived3"<<endl;}
};

void main()
{
        Derived *Var = new Derived2();
        delete (Derived3*)Var;  //<---- this should cause some type of run-time error
}

Why does the above not generate an error. Is it because there is not data in Derived3 to release. Or am I missing something?
But instead it outputs

C: Base
C: Derived
C: Derived2
D : Derived3       <--- SHOULD NOT BE POSSIBLE
D : Derived2
D : Derived
D : Base

Upvotes: 3

Views: 747

Answers (4)

AnT stands with Russia
AnT stands with Russia

Reputation: 320719

C++ language doesn't have any extensive system of "run-time errors". Some language features can throw exceptions or call terminate(), which are "run-time errors" indeed, but invalid delete is not one of these features.

Doing something as invalid as what you are dong is causing undefined behavior in C++. Undefined behavior means that anything can happen, anything is possible. Your program might even behave as if it is "working" in some way. This is what you observe.

Experimenting with undefined behavior is a pointless exercise. The results you observe mean absolutely nothing and are generally not repeatable.

Upvotes: 6

Steve Guidi
Steve Guidi

Reputation: 20198

Your cast to Derived3 is a C-style cast which is effectively the same as the following C++-style cast.

delete reinterpret_cast<Derived3*>(Var);

Both of these casts tell the C++ runtime that you want to force the runtime to interpret the memory referenced by the cast (Var) as the given type (Derived3*) and fully understand the repercussions. Consequently, no error checking is performed.

If you are concerned about the validity of the cast, use the following:

static_cast<Derived3*>(Var) : Generates a compilation error if the cast is invalid. dynamic_cast<Derived3*>(Var) : Returns 0 (null) if the cast is invalid.

Upvotes: 2

aschepler
aschepler

Reputation: 72463

Undefined Behavior can do anything, including appearing to work. It's not the job of the compiler or runtime to complain if you did something illegal, just to do the right things if you didn't do anything illegal.

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564811

It isn't causing an error because your destructor doesn't change or touch any local state.

In a typical destructor, you would free some resource allocated by that instance, which would cause the problems you'd expect.

That being said, it's still not good code, and only occurs because you're explicitly casting to the incorrect type. The behavior is technically undefined in this case, which means anything can happen, including "working" as it's doing now.

Upvotes: 0

Related Questions