0

假设我们有一个具体类 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。请随意质疑我的逻辑和这个设计示例,但问题仅与指针对齐有关.

4

4 回答 4

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 都应该有虚函数或至少有虚析构函数。否则就没有合法的方式来进行类型转换。

于 2011-04-15T07:38:35.567 回答
2

拥有大量不相关的类,这些类既派生自AB是一个非常奇怪的设计。如果有一些东西可以制造A并且B总是“一起使用”,您可以合并它们或引入一个仅从它们派生然后仅从该类派生的垫片类:

class Shim : A, B {};

class DerivedX : Shim {};

在后一种情况下,您只需使用static_castto 首先向下转换 fromABto Shim*然后 C++ 它将隐式地将Shim*指针转换为另一个类。

于 2011-04-15T07:38:17.620 回答
0

如果您想在函数中同时使用 A 类和 B 类的功能,那么您应该修改函数以接收 C 指针:

void foo(C* c);

通常,您假设“每个 B 也是 A”是错误的。您可以创建从 B 接口派生的类,而不是从 A 类派生的类,这就是为什么编译器不会知道在您的特定情况下“每个 B 都是 A”。

于 2011-04-15T07:49:21.420 回答
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

But I suspect that if you always need to implement both A and B, you should create a single interface with both, either by inheriting, or coalising both into a single class; your B1 and B2 would inherit from that. (The solution with dynamic_cast, of course, is for the case where the derived class of B may or may not also derived from A.)

于 2011-04-15T08:54:29.770 回答