Downcasting in oops

class Parent
{};
class A_child : public Parent
{
  void A_method();
};
class B_child : public Parent
{
  void B_method();
};
void main()
{
  A_child a;
  Parent *p = &a;
  B_child *b = (B_child*)&p;
  b->B_method();
}

This piece of code is in C++. It is a logical error as we are trying to cast a "Cat" into a "Dog". But it works. Can anyone explain why and how?

Upvotes: 0

Views: 129

Answers (2)

zzxyz
zzxyz

Reputation: 2981

This is likely but not guaranteed to not cause an error because your B_method is effectively static.

  1. The method can be looked up and called into without dereferencing the class pointer
  2. The method itself doesn't need to dereference the class pointer.

As soon as the method becomes virtual (and now requires the class pointer for access to the vtable to look up the function address), accesses class data, or you sneeze or look at the compiler funny, you will be dealing unbound memory access.

And I should stress that while dereferencing the class pointer is not required by a hypothetical compiler, it is allowed, and could be required by any particular compiler implementation.

Further reading...check out the accepted answer Difference between Object and instance : C++ Your class pointer is unlikely to be looked at until you access instance data associated with a particular instance of the class.

Or...another way to put all this. If you can tack on static in front of your function declaration, calling it with an invalid pointer might work.

See also:

class MyClass
{
public:
  int doSomething(int x)
  {
    printf("%d", x);
    return x;
  }
};

int main()
{
  MyClass *pMyClass = nullptr;
  pMyClass->doSomething(42);
}

Upvotes: 3

eerorika
eerorika

Reputation: 238461

Can anyone explain why and how?

Parent is a base of B_child and so the conversion from the type Parent *p to B_child* is well formed. However, the behaviour of accessing the pointed object through this converted pointer is only defined if p actually does point to a base sub object of a B_child instance.

The precondition does not hold, and so the behaviour of the program is undefined. Possible behaviours include, none of which are guaranteed:

 - working
 - not working
 - random output
 - non-random output
 - the expected output
 - unexpected output
 - no output
 - any output
 - crashing at random
 - crashing always
 - not crashing at all
 - corruption of data
 - different behaviour, when executed on another system
 -                    , when compiled with another compiler
 -                    , on tuesday
 -                    , only when you are not looking
 - same behaviour in any or all of the above cases
 - anything else within the power of the computer (hopefully limited by the OS)

Never static_cast, reinterpret_cast or C-style cast an expression to another type unless you can prove that the cast is correct. You can use dynamic_cast in a case where you're unsure.

Upvotes: 5

Related Questions