2

I need to derive a child class CDerived from two different base classes CBaseA and CBaseB.

In addition, I need to call virtual functions of both parents on the derived class. Since I want to manage differently typed objects in one single vector later (this is not part of this minimal code expample), I need to call the virtual functions from a base class pointer to the derived class object:

#include <iostream>
#include <stdlib.h>

class CBaseA
{
  public:
    virtual void FuncA(){ std::cout << "CBaseA::FuncA()" << std::endl; };
};

class CBaseB
{
  public:
    virtual void FuncB(){ std::cout << "CBaseB::FuncB()" << std::endl; };
};

class CDerived : public CBaseB, public CBaseA
{};

int main( int argc, char* argv[] )
{
  // An object of the derived type:
  CDerived oDerived;

  // A base class pointer to the object, as it could later
  // be stored in a general vector:
  CBaseA* pAHandle = reinterpret_cast<CBaseA*>( &oDerived );

  // Calling method A:
  pAHandle->FuncA();

  return 0; 
}

Problem: But when running this on my computer, FuncB() is called instead of FuncA(). I get the right result, if I "flip" the parent class deklarations around, i.e.

class CDerived : public CBaseA, public CBaseB

but this doesn't solve my problem, since I cannot be sure which function will be called.

So my question is: What am I doing wrong and what is the correct way of handling such a problem?

(I am using g++ 4.6.2, by the way)

2 Answers 2

7
CBaseA* pAHandle = reinterpret_cast<CBaseA*>( &oDerived );

Do not use reinterpret_cast for performing a conversion to a base class. No cast is required; the conversion is implicit:

CBaseA* pAHandle = &oDerived;

For converting to a derived class, use static_cast if the object is known to be of the target type or dynamic_cast if it is not.

Your use of reinterpret_cast yields undefined behavior, hence the "odd" behavior that you see. There are few correct uses of reinterpret_cast and none of them involve conversions within a class hierarchy.

Sign up to request clarification or add additional context in comments.

4 Comments

In fact, there are no correct uses of reinterpret_cast that don't involve casting it back to the old type before doing anything with it.
@DirkHolsopple: There are other valid uses. For example, any object may be reinterpreted as an array of bytes.
I was referring to portable uses. Reinterpreting an object as an array of bytes is inherently platform-specific.
Interesting Conversions covered by the standard: 5.2.10.4 & 5: Converting a pointer to an integral type and back. 5.2.10.11: Casting a T object to T& or T&&. 9.2.20: "A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa." 26.4.4: Using reinterpret_cast for complex<T> types. Also 3.9.2 sort of implies (and gives reasons for) James McNellis' example.
2

Common implementation which may help you to understand what happens.

CBaseA in memory look like this

+---------+
| __vptrA |
+---------+

CBaseB in memory looks like this

+---------+
| __vptrB |
+---------+

CDerived looks like this:

             +---------+
&oDerived->  | __vptrB |
             | __vptrA |
             +---------+

If you simply assign &oDerived to a CBaseA*, the compiler puts code to add the offset so that you have

             +---------+
&oDerived--->| __vptrB |
pAHandle---->| __vptrA |
             +---------+

an during execution the program find pointers to A virtual function in __vptrA. If you static_cast or dynamic_cast pAHandle back to a CDerived (or even dynamic_cast pAHandle to a CBaseA), the compiler will put code to subtract the offset so that the result point to the start of the object (dynamic_cast will find the information about how much to substract in the vtable along with the pointers to virtual functions).

When you reinterpret_casted &oDerived as a CBaseA*, the compiler don't put such code to adjust the pointer, you get

                       +---------+
pAHandle, &oDerived--->| __vptrB |
                       | __vptrA |
                       +---------+

and during the execution, the program looked at __vptrB for A virtual function, finding instead B virtual functions.

1 Comment

Thank you, this helps me to understand the class pointer casting issue a lot better. This piece of information is difficult to find in the internet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.