Multiple Inheritance: Unexpected Result After Cast from Void * to 2Nd Base Class

multiple inheritance: unexpected result after cast from void * to 2nd base class

It's not a compiler bug - it's what reinterpret_cast does. The DecoratedSquare object will be laid out in memory something like this:

Square
Decorated
DecoratedSquare specific stuff

Converting a pointer to this to void* will give the address of the start of this data, with no knowledge of what type is there. reinterpret_cast<Decorated*> will take that address and interpret whatever is there as a Decorated - but the actual memory contents are the Square. This is wrong, so you get undefined behaviour.

You should get the correct results if you reinterpret_cast to the correct dynamic type (that is DecoratedSquare), then convert to the base class.

cast void* to classes with multiple inheritance

The problem with your code is that your shared pointers are null, and therefore behaviour of indirecting through them is undefined.

You can create shared objects using std::make_shared.

Keep in mind however, that the shared objects are destroyed as soon as last shared pointer is destroyed, at which point any pointers to the objects in your map (if any) are left dangling.

Static cast to base class gives unexpected results when base has a virtual function

The compiler is free to lay out your classes however it likes, presumably your compiler always puts virtual classes at the beginning and any non-virtual classes after that.

You can't rely on any particular ordering of classes.

Vector of elements from multiple classes that have the same base class

When you give a copy of DerivedClass into a vector containing pointers of BaseClass, you're essentially downcasting the pointer inside the vector to a BaseClass object, meaning that that you lose all the DerivedClass type information (methods, members, etc). While the DerivedClass contents will still be there, they'll no longer be accessible.

Take the following example:

class MyBaseClass
{
public:
MyBaseClass();
virtual ~MyBaseClass();

void SetValue(const int value);
int GetValue() const;

private:
int m_value;
};

class MyDerivedClass : public MyBaseClass
{
public:
MyDerivedClass();
virtual ~MyDerivedClass();

void SetExtraValue(const std::string &value);
std::string GetExtraValue() const;

private:
std::string m_extraValue;
};

Every variable created of "MyBaseClass" only guarantees that the SetValue and GetValue methods are available. Every variable created of MyDerivedClass guarantees that 4 methods are available, the two methods from the base class, and the SetExtraValue and GetExtraValue methods.

If you create a vector of MyBaseClass pointers, you're only guaranteeing that the methods SetValue and GetValue are going to be available on the contents of that vector, EVEN IF THE CONTENTS ARE ALL MyDerivedClass.

Consider this modified version of your example:

QVector<basicClass*> vectorINeed;
basicClass *object= new basicClass(); // <--- Create basicClass instance instead of derivedClass1 instance.

qDebug() << object->basicClass::seta(true);

vectorINeed.append(object);

qDebug() << vectorINeed[0]->basicClass::seta(true);
qDebug() << vectorINeed[0]->derivedClass1::methodInClass1(); // <--- What would happen here?

The compiler cannot guarantee that the object inside the vector is a derivedClass1 object, only a basicClass object, therefore it cannot guarantee that the methodInClass1 method will be available.

As I see it, you've got three options:

  1. Change the vector declaration to QVector<derivedClass1 *> vectorINeed if you can. Or...
  2. Run your methods against object rather than vectorINeed[0].
  3. If you can guarantee that the contents of the vector will ALWAYS be of type derivedClass1, you can use the dynamic_cast function to perform a cast to derivedType before doing methodInClass1.


Related Topics



Leave a reply



Submit