参见英文答案 > Conversion from void* to the pointer of the base class 4个
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 * s来自DWORD_PTR CTreeCtrl :: GetItemData(),所以这就是我使用void *的原因.由于我有无效*,我没有关于类的确切类型的信息.
在可怕的钻石问题之前,只有X,A,B,C-Classes和没有虚拟的interitance,因此有可能将它们转换为X,因为它是公共基类,它首先出现在派生类列表中(I知道这是未定义的行为,但它确实有效).
解决方案1 :(最简单,最正确的解决方案)
在void * -Pointers中存储D1和D2地址之前,将它们转换为公共基类.之后,向下投射工作,这也不是一个未定义的行为.
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-class将首先在内存中.仅使用VS2015进行测试
最佳答案 在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