C ++指针多继承的乐趣

时间:2010-01-28 18:58:53

标签: c++ multiple-inheritance

我正在编写一些涉及从基本引用计数指针类继承的代码;并且出现了一些复杂的C ++。我把它减少如下:

假设我有:

class A{};
class B{};
class C: public A, public B {};

C c;
C* pc = &c;
B* pb = &c;
A* pa = &c;

// does pa point to a valid A object?
// does pb point to a valid B object?

// does pa == pb ?

此外,确实:

// pc == (C*) pa ?
// pc == (C*) pb ?

谢谢!

5 个答案:

答案 0 :(得分:8)

  
      
  • 是否指向有效的A对象?
  •   
  • pb是否指向有效的B对象?
  •   

是的,C*会被转换,以便papb指向正确的地址。

  
      
  • 是pa == pb?
  •   

不,通常不会。在同一地址不能有A个对象和B个对象。

  

此外,

     
      
  • pc ==(C *)pa?
  •   
  • pc ==(C *)pb?
  •   

强制转换将指针转换回C对象的地址,因此两个等式都为真。

答案 1 :(得分:2)

C嵌入AB

class C: public A, public B {};

与C代码非常相似

struct C {
    A self_a;
    B self_b;
};
如果您使用直接C,则

(B*) &c;相当于static_cast< B* >( &c )类似于&c.self_b

一般来说,你不能依赖指向不同类型的指针,这些指针可以互换或比较。

答案 2 :(得分:1)

pc == pa;
pc == pb;

未定义,取决于类结构。

pc == (C*) pa;
pc == (C*) pb;

好的。

pa == pb;

没有

他们是否指向有效对象?

Yes

答案 3 :(得分:1)

Item 28 Meaning of Pointer Comparison中的

C++ Common Knowledge: Essential Intermediate Programming解释了C ++中对象指针的关键:

  

在C ++中,对象可以有多个有效地址,而指针比较不是关于地址的问题。这是一个关于对象身份的问题。

看看代码:

class A{};
class B{};
class C: public A, public B {};

C c;
C* pc = &c;
B* pb = &c;
A* pa = &c;

class C来自class Aclass B,因此class C同时为class Aclass B。对象C c有3个有效地址:class Aclass Bclass C的地址。实现取决于编译器,因此您不能假设class C的内存布局,它可能是这样的:

 ----------  <- pc (0x7ffe7d10e1e0)
 |        |
 ----------  <- pa (0x7ffe7d10e1e4)
 | A data |
 ----------  <- pb (0x7ffe7d10e1e8)
 | B data |
 ----------
 | C data |
 ----------

在上述情况下,虽然pcpapb的地址值不相同,但它们都引用同一个对象(c),所以编译器必须确保pcpapb相等,即pc == papc == pb。编译器通过调整被比较的指针之一的值通过适当的偏移量来完成此比较。例如,

pc == pa

被翻译为:

pc ? ((uintptr_t)pc + 4 == (uintptr_t)pa) : (pa == 0)

除其他事项外,由于AB没有继承关系,因此我们无法直接比较papb

对于你的问题:

(1) does pa point to a valid A object?  
(2) does pb point to a valid B object?  
Yes, refer the above diagram. 

(3) pc == (C*) pa ?  
(4) pc == (C*) pb ?  
Yes, No need to add (C*).

(5) does pa == pb ?
No. We can't compare them.

答案 4 :(得分:0)

你得到的就是这样的内存

 ----------
 | A data |
 ----------
 | B data |
 ----------
 | C data |
 ----------

因此,如果您想要整个C对象,您将获得指向内存开头的指针。如果您只想要A“部分”,那么您将获得相同的地址,因为数据成员所在的地址。如果你想要B“部分”你得到开头+ sizeof(A)+ sizeof(无论编译器为vtable添加什么)。 因此,在示例中,pc!= pb(可能是pc!= pa)但pa永远不等于pb。