Yus*_*göz 5 c++ casting multiple-inheritance virtual-inheritance
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;
Run Code Online (Sandbox Code Playgroud)
这些(演员 1 和演员 2)演员阵容正确吗?(除了未定义的行为。)如果没有确切的类类型信息,我应该如何将它们转换为基类?
编辑1:
请在将问题标记为重复或回答之前先阅读该问题。基类是虚拟的。这是可怕的钻石问题!
请不要关注C-Cast。我知道 static/dynamic/reinterpret_cast 是什么。
编辑2:
void *s 来自 a DWORD_PTR CTreeCtrl::GetItemData(),所以这就是我使用void *. 正如我所拥有的void *那样,我没有关于课程的确切类型的信息。
在可怕的钻石问题之前,只有X, A, B, C-Classes 而没有虚拟继承,因此可以将它们转换为X,因为它是公共基类,在派生类列表中排在第一位(我知道这是未定义的行为,但它作品)。
解决方案1:(最简单且正确的解决方案)
在存储D1和D2寻址void *-Pointers 之前,将它们转换为公共基类。之后,向下转换起作用,而且这也不是未定义的行为。
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
Run Code Online (Sandbox Code Playgroud)
解决方案2:(包装类)
存储指向包装类的空指针,该类保存指向基类的指针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
Run Code Online (Sandbox Code Playgroud)
测试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
Run Code Online (Sandbox Code Playgroud)
我认为通过虚拟继承,第一个虚拟基B类将首先位于内存中。仅使用 VS2015 进行测试
在 C++ 中,不鼓励使用void*,另一方面,最好使用static_cast<T>()和dyanmic_cast<T>()。
换句话说,正确的方法是:
A* pA1 = dynamic_cast<A*>(new D1);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器可以检查A和D1之间的关系
如果必须处理void*,最好使用static_cast<T>()重新转换为原始类型,然后再转换为基类。
void* pD1 = new D1;
A* pA1 = dynamic_cast<A*>(static_cast<D1*>(pD1));
Run Code Online (Sandbox Code Playgroud)
编译器除了相信你会给出正确的类之外别无选择......
dynamic_cast一个void*不起作用。
有关 C++ 强制转换的更多信息:检查此问题
| 归档时间: |
|
| 查看次数: |
1289 次 |
| 最近记录: |