c – 如何从void *转换为没有确切类型信息的虚拟基类?

参见英文答案 > 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

点赞