class A : public X;
class B : public virtual A;
class C : public virtual A;
class D1 : public B, public C;
class D2 : public B, public C;
void *p1 = new D1; //after storing the pointers,
void *p2 = new D2; //there will be no exact type info.
A *pA1 = (A *) p1; // Cast 1
A *pA2 = (A *) p2;
X *pX1 = (X *) p1; // Cast 2
X *pX2 = (X *) p2;
Are those (Cast 1 and Cast 2) casts correct? (except Undefined behavior.) How should i cast them into base classes without exact class type info?
Edit 1:
Please read the question before you mark it as duplicate or answer it. Base class is virtual. It is dreaded diamond problem!
Please don't focus on C-Cast. I know what static/dynamic/reinterpret_cast are.
Edit 2:
void *
s are coming from a DWORD_PTR CTreeCtrl::GetItemData()
, so it is why i'm using void *
. As i'm having void *
's, i have no information about the exact type of classes.
Before dreaded diamond problem, there were only X, A, B, C
-Classes and no virtual interitance, so it was possible to cast them into X
, because it was the common base class, which comes first in the derived class list (I know this is undefined behavior, but it works).
Solution 1: (Easiest and the correct solution)
Before storing D1
and D2
adresses in void *
-Pointers, casting them into common base class. After that, down casting works and also this is not an undefined behavior.
void *p1 = static_cast<X *>(new D1); //or cast to other common base class 'A'
//p2 is the same...
X *pX1 = (X *) p1; //static/reinterpret_cast is better.
//then down cast attempts are possible.
dynamic_cast<D1 *>(pX1); //returns valid pointer
dynamic_cast<D2 *>(pX1); //returns nullptr
Solution 2: (Wrapper class)
Storing a void pointer to wrapper class which holds a pointer to base class X
or A
is also possible. Like boost::any
Test 1: (Before virtual inheritance)
If there is no virtual inheritance. We have only X, A, B, C
-classes.
B b;
C c;
void *pB = &b;
void *pC = &c;
X *pX1 = (X *) pB;
X *pX2 = (X *) pC;
assert(&b == dynamic_cast<B *>(pX1)); // OK
assert(&c == dynamic_cast<C *>(pX2)); // OK
Test 2: (After virtual inheritance) D1 d1; D2 d2;
void *pD1 = &d1;
void *pD2 = &d2;
X *pX1 = (X *) pD1;
X *pX2 = (X *) pD2;
A *pA1 = (A *) pD1;
A *pA2 = (A *) pD2;
B *pB1 = (B *) pD1;
B *pB2 = (B *) pD2;
C *pC1 = (C *) pD1;
C *pC2 = (C *) pD2;
assert(&d1 == dynamic_cast<D1 *>(pB1)); //OK
assert(&d2 == dynamic_cast<D2 *>(pB2)); //OK
assert(&d1 == dynamic_cast<D1 *>(pC1)); //Fails
assert(&d2 == dynamic_cast<D2 *>(pC2)); //Fails
assert(&d1 == dynamic_cast<D1 *>(pX1)); //Access violation by casting
assert(&d2 == dynamic_cast<D2 *>(pX2)); //Access violation by casting
assert(&d1 == dynamic_cast<D1 *>(pA1)); //Access violation by casting
assert(&d2 == dynamic_cast<D2 *>(pA2)); //Access violation by casting
I think by a virtual inheritance, first virtual base B
-class will be at first in memory. Tested only with VS2015