处理多重继承时如何对齐指针?

发布于 2024-11-02 01:05:01 字数 578 浏览 6 评论 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。请随意质疑我的逻辑和这个设计示例也是如此,但问题仅涉及指针对齐。

Say we have a concrete class A, and an abstract class B.

Consider a concrete C, that inherits from both A and B, and implements B:

class C : public A, public B  
{  
/* implementation of B and specific stuff that belongs to C */  
};

Now I define a function which signature is void foo(B* b);

This is my code, I can assume that every pointers to B are both A and B.
In foo's definition, how to get a pointer to A?
A nasty but working trick is to align back pointers like so:

void foo(B* b)  
{  
    A* a = reinterpret_cast<A*>(reinterpret_cast<char*>(b) - sizeof(A));
    // now I can use all the stuff from A  
}

Keep in mind that C does not have a super type and actually, there are many classes akin to C which only are A and B. Feel free to question both my logic and this sample of design as well but the question is only concerning pointers alignment.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

余生共白头 2024-11-09 01:05:01
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 都应该有虚拟函数或至少有虚拟析构函数。否则就没有合法的方法来进行类型转换。

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
    }
}

Forgot to say: in order to make work dynamic cast both A and B should have virtual function(s) or at least virtual destructors. Otherwise there is no legal way to do that type conversion.

待天淡蓝洁白时 2024-11-09 01:05:01

拥有大量从 AB 派生的不相关的类是一个非常奇怪的设计。如果有什么东西使 AB 始终“一起使用”,您可以合并它们或引入一个填充类 em> 仅从它们派生,然后仅从该类派生:

class Shim : A, B {};

class DerivedX : Shim {};

在后一种情况下,您只需使用 static_cast 首先从 AB 向下转换code> 到 Shim*,然后 C++ 会隐式地将 Shim* 指针转换为另一个类。

Having a huge set of unrelated classes that both derive from A and B is a very strange design. If there's something that makes A and B always be "used together" you could either merge them or introduce a shim class that only derives from them and then only derive from that class:

class Shim : A, B {};

class DerivedX : Shim {};

and in the latter case you just use static_cast to first downcast from A or B to Shim* and then C++ it will implicitly convert the Shim* pointer to the other class.

故事和酒 2024-11-09 01:05:01

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

void foo(C* c);

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

If you want to use the functionality of both class A and Class B in your function then you should modify the function to receive C pointers:

void foo(C* c);

And in general you are wrong with you assumption that "every B is an A as well". You could create classes derived from you B interface and not derived from Class A, that's why the compiler won't know that in your specific case "every B is an A".

享受孤独 2024-11-09 01:05:01

扩展 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
{
};

B1B2 必须实际上从 B 派生。

但我怀疑如果你总是需要同时实现 A
B,您应该创建一个包含两者的界面,或者通过
继承或将两者合并为一个类;您的 B1
B2 将从中继承。 (解决方案与
dynamic_cast 当然,是针对派生的情况
B 的类可能也可能不是从 A 派生的。)

Expanding on sharptooth's answer (and entering it as an answer, because I can't get formatted code into a comment), you can still use the shim:

class Shim : public virtual A, public virtual B {};

Then:

class Derived1 : public Shim, public virtual A, public virtual B1
{
};

class Derived2 : public Shim, public virtual A, public virtual B2
{
};

B1 and B2 must derive virtually from 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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文