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;
那些(演员1和演员阵容2)演员是否正确? (未定义的行为除外。) 如何在没有确切类类信息的情况下将它们转换为基类?
修改1:
请在将问题标记为重复或回答之前阅读该问题。基类是虚拟的。这是可怕的钻石问题!
请不要专注于C-Cast。我知道static / dynamic / reinterpret_cast是什么。
编辑2:
void *
来自DWORD_PTR CTreeCtrl::GetItemData()
,所以这就是我使用void *
的原因。由于我有void *
,我没有关于类的确切类型的信息。
在可怕的钻石问题之前,只有X, A, B, C
- 类,没有虚拟干扰,因此有可能将它们转换为X
,因为它是公共基类,它首先出现在派生类列表(我知道这是未定义的行为,但它有效)。
解决方案1:(最简单,最正确的解决方案)
在D1
- 指针中存储D2
和void *
地址之前,将它们转换为公共基类。在那之后,向下投射工作,这也不是一个未定义的行为。
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
解决方案2:(包装类)
存储一个void指针,指向包含指向基类X
或A
的指针的包装类也是可能的。与boost::any
测试1:(在虚拟继承之前)
如果没有虚拟继承。我们只有X, A, B, C
- 类。
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
测试2:(虚拟继承后) 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
我认为通过虚拟继承,第一个虚拟基础B
- 类将首先在内存中。仅使用VS2015进行测试
答案 0 :(得分:2)
在c ++中,不鼓励使用void*
,另一方面,最好使用static_cast<T>()
和dyanmic_cast<T>()
。
换句话说,正确的方法是:
A* pA1 = dynamic_cast<A*>(new D1);
在这种情况下,编译器可以检查A和D1之间的关系
如果必须处理void*
,最好使用static_cast<T>()
重新转换为原始类型,然后再转换为基类。
void* pD1 = new D1;
A* pA1 = dynamic_cast<A*>(static_cast<D1*>(pD1));
编译器别无选择,只相信你会给出正确的类......
dynamic_cast
void*
不起作用。
有关c ++强制转换的更多信息:check this question