我正在编写一些涉及从基本引用计数指针类继承的代码;并且出现了一些复杂的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 ?
谢谢!
答案 0 :(得分:8)
- 是否指向有效的A对象?
- pb是否指向有效的B对象?
是的,C*
会被转换,以便pa
和pb
指向正确的地址。
- 是pa == pb?
不,通常不会。在同一地址不能有A
个对象和B
个对象。
此外,
- pc ==(C *)pa?
- pc ==(C *)pb?
强制转换将指针转换回C
对象的地址,因此两个等式都为真。
答案 1 :(得分:2)
C
嵌入A
和B
。
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)
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 A
和class B
,因此class C
同时为class A
和class B
。对象C c
有3个有效地址:class A
,class B
和class C
的地址。实现取决于编译器,因此您不能假设class C
的内存布局,它可能是这样的:
---------- <- pc (0x7ffe7d10e1e0)
| |
---------- <- pa (0x7ffe7d10e1e4)
| A data |
---------- <- pb (0x7ffe7d10e1e8)
| B data |
----------
| C data |
----------
在上述情况下,虽然pc
,pa
和pb
的地址值不相同,但它们都引用同一个对象(c
),所以编译器必须确保pc
与pa
和pb
相等,即pc == pa
和pc == pb
。编译器通过调整被比较的指针之一的值通过适当的偏移量来完成此比较。例如,
pc == pa
被翻译为:
pc ? ((uintptr_t)pc + 4 == (uintptr_t)pa) : (pa == 0)
除其他事项外,由于A
和B
没有继承关系,因此我们无法直接比较pa
和pb
。
对于你的问题:
(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。