简体   繁体   English

C ++指针多继承的乐趣

[英]C++ pointer multi-inheritance fun

I'm writing some code involving inheritance from a basic ref-counting pointer class; 我正在编写一些涉及从基本引用计数指针类继承的代码; and some intricacies of C++ popped up. 并且出现了一些复杂的C ++。 I've reduced it as follows: 我把它减少如下:

Suppose I have: 假设我有:

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 ?

Furthermore, does: 此外,确实:

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

Thanks! 谢谢!

  • does pa point to a valid A object? pa指向有效的A对象?
  • does pb point to a valid B object? pb是否指向有效的B对象?

Yes, the C* gets converted so that pa and pb point to the correct addresses. 是的, C*被转换,以便papb指向正确的地址。

  • does pa == pb ? pa == pb?

No, usually not. 不,通常不是。 There can't be an A object and a B object at the same address. 在同一地址不能有A对象和B对象。

Furthermore, does 此外,是吗

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

The cast converts the pointers back to the address of the C object, so both equalities are true. 强制转换将指针转换回C对象的地址,因此两个等式都为真。

C embeds an A and a B . C嵌入AB

class C: public A, public B {};

is very similar to the C code 与C代码非常相似

struct C {
    A self_a;
    B self_b;
};

and (B*) &c; (B*) &c; is equivalent to static_cast< B* >( &c ) is similar to &c.self_b if you were using straight C. 相当于static_cast< B* >( &c )类似于&c.self_b如果你直接使用C.

In general, you can't rely on pointers to different types being interchangeable or comparable. 通常, 您不能依赖指向不同类型的指针,这些指针是可互换的或可比较的。

pc == pa;
pc == pb;

Not defined, depends on class structure. 未定义,取决于类结构。

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

Thats ok. 没关系。

pa == pb;

No. 没有。

Do they point to valid objects? 他们指向有效的对象吗?

Yes

Item 28 Meaning of Pointer Comparison in C++ Common Knowledge: Essential Intermediate Programming ) explains the key of object pointer in C++: 项目28 C ++ 中指针比较的含义 常识:基本中间编程 )解释了C ++中对象指针的关键:

In C++, an object can have multiple, valid addresses, and pointer comparison is not a question about addresses. 在C ++中,对象可以有多个有效地址,指针比较不是关于地址的问题。 It's a question about object identity. 这是一个关于对象身份的问题。

Take a look at the code: 看看代码:

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

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

class C derives from both class A and class B , so class C is both class A and class B . class C源自class Aclass B ,因此class C class A既是class A class B the object C c has 3 valid addresses: address for class A , class B and class C . 对象C c有3个有效地址: class A class B class Cclass C class B地址。 The implementation depends on compiler, so you can't assume the memory layout of class C , and it may like this: 实现依赖于编译器,因此您不能假设class C的内存布局,它可能是这样的:

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

In above case, although the address value of pc , pa and pb aren't same, they all refer to the same object ( c ), so the compiler must ensure that pc compares equal to both pa and pb , ie, pc == pa and pc == pb . 在上面的例子中,尽管pcpapb的地址值不相同,但它们都引用相同的对象( c ),因此编译器必须确保pc比较等于papb ,即pc == papc == pb The compiler accomplishes this comparison by adjusting the value of one of the pointers being compared by the appropriate offset. 编译器通过调整被比较的指针之一的值通过适当的偏移量来完成此比较。 Eg, 例如,

pc == pa

is translated to: 被翻译成:

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

Among other things, since A and B have no inheritance relationship, we can't compare pa and pb directly. 除此之外,由于AB没有继承关系,我们无法直接比较papb

For your questions: 对于你的问题:

(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.

What you get is something like this in memory 你得到的是记忆中的这样的东西

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

So if you want the entire C object you'll get a pointer to the beginning of the memory. 因此,如果您想要整个C对象,您将获得指向内存开头的指针。 If you want only the A "part", you get the same address since that's where the data members are located. 如果您只想要A“部分”,那么您将获得相同的地址,因为数据成员所在的地址。 If you want the B "part" you get the beginning + sizeof(A) + sizeof(whatever the compiler adds for vtable). 如果你想要B“部分”你得到开头+ sizeof(A)+ sizeof(无论编译器为vtable添加什么)。 Thus, in the example, pc != pb (could be pc != pa) but pa is never equal to pb. 因此,在这个例子中,pc!= pb(可能是pc!= pa)但是pa永远不等于pb。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM