假设我们有一个具体的类A和一个抽象类B.
考虑一个具体的C,它继承自A和B,并实现B:
class C : public A, public B
{
/* implementation of B and specific stuff that belongs to C */
};
现在我定义一个签名为void foo(B* b);
这是我的代码,我可以假设每个指向B的指针都是A和B. 在foo的定义中,如何获得指向A的指针? 一个讨厌但有效的技巧是将指针对齐,如下所示:
void foo(B* b)
{
A* a = reinterpret_cast<A*>(reinterpret_cast<char*>(b) - sizeof(A));
// now I can use all the stuff from A
}
请记住,C没有超类型,实际上,有许多类似于C的类,只有A和B.可以自由地质疑我的逻辑和设计样本,但问题只是关于指针对齐。
答案 0 :(得分:6)
void foo(B* b)
{
//A* a = reinterpret_cast<A*>(reinterpret_cast<char*>(b) - sizeof(A)); // undefined behaviour!!!!
A* a = dynamic_cast<A*>(b);
if (a)
{
// now I can use all the stuff from A
}
else
{
// that was something else, not descended from A
}
}
忘了说:为了使工作动态转换,A和B应该具有虚函数或至少虚拟析构函数。否则,没有合法的方法来进行类型转换。
答案 1 :(得分:2)
拥有大量不相关的类,这些类都来自A
和B
,这是一个非常奇怪的设计。如果某些内容使A
和B
始终“一起使用”,您可以合并它们或引入一个仅从派生的派生类他们然后只派出那个班级:
class Shim : A, B {};
class DerivedX : Shim {};
在后一种情况下,您只需使用static_cast
从A
或B
向Shim*
进行首播,然后使用C ++隐式转换Shim*
指向另一个类的指针。
答案 2 :(得分:0)
如果你想在你的函数中使用A类和B类的功能,那么你应该修改函数来接收C指针:
void foo(C* c);
一般来说,你错误地认为“每个B都是A”。您可以创建从您的B接口派生而不是从A类派生的类,这就是编译器在您的特定情况下不会知道“每个B都是A”的原因。
答案 3 :(得分:0)
扩展sharptooth的答案(并将其作为答案输入,因为我无法将格式化的代码添加到评论中),您仍然可以使用垫片:
class Shim : public virtual A, public virtual B {};
然后:
class Derived1 : public Shim, public virtual A, public virtual B1
{
};
class Derived2 : public Shim, public virtual A, public virtual B2
{
};
B1
和B2
必须来自B
。
但我怀疑如果你总是需要实现A
和。{
B
,你应该用两者创建一个单独的接口
继承或合并为一个班级;你的B1
和
B2
将从中继承。 (解决方案
当然,dynamic_cast
是针对派生的情况
B
的类可能也可能不会从A
派生。)