C++ C++;指针多重继承乐趣
我正在编写一些代码,涉及从基本引用计数指针类继承;一些复杂的C++出现了。我将其缩减如下: 假设我有:C++ C++;指针多重继承乐趣,c++,multiple-inheritance,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 =
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 ?
谢谢
- pa是否指向有效的a对象
- pb是否指向有效的B对象
C*
被转换成pa
和pb
指向正确的地址
- pa=pb吗
A
对象和B
对象
再者,你认为呢
- pc==(C*)帕
- pc==(C*)pb
C
对象的地址,因此这两个等式都为真
pc == pa;
pc == pb;
未定义,取决于类结构
pc == (C*) pa;
pc == (C*) pb;
没关系
pa == pb;
没有
它们是否指向有效的对象
Yes
C
嵌入一个A
和一个B
class C: public A, public B {};
与C代码非常相似
struct C {
A self_a;
B self_b;
};
和(B*)&c
相当于static\u cast(&c)
类似于&c.self\u B
,如果您使用的是纯c
一般来说,您不能依赖指向不同类型的指针,这些指针是可互换的或可比较的。您在内存中得到的是这样的东西
----------
| A data |
----------
| B data |
----------
| C data |
----------
因此,如果你想要整个C对象,你会得到一个指向内存开头的指针。如果您只需要A“part”,则会得到相同的地址,因为数据成员位于该地址。如果你想要B“part”,你可以得到开头+sizeof(A)+sizeof(无论编译器为vtable添加了什么)。
因此,在示例中,pc!=pb(可以是pc!=pa),但pa永远不等于pb。in)解释了C++中对象指针的键:
<>在C++中,对象可以有多个有效的地址,而指针比较不是关于地址的问题。这是一个关于对象身份的问题
看看代码:
class A{};
class B{};
class C: public A, public B {};
C c;
C* pc = &c;
B* pb = &c;
A* pa = &c;
C类
既源于A类
又源于B类
,因此C类
既是A类
又是B类
。对象C
有3个有效地址:A类地址、B类地址和C类
地址。实现取决于编译器,因此您不能假定类C
的内存布局,它可能如下所示:
---------- <- pc (0x7ffe7d10e1e0)
| |
---------- <- pa (0x7ffe7d10e1e4)
| A data |
---------- <- pb (0x7ffe7d10e1e8)
| B data |
----------
| C data |
----------
翻译为:
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.
你所说的==是什么意思?显然,地址是相同的。地址不一定完全相同。在我所看到的多重继承(虚拟)的一个实现中,在派生类对象的基址上添加了一些偏移量,以访问B的属性和方法。但是,当编译器在内部操纵它时,用户看不到这一点。因此,在您的程序中,您可能仍然会看到A、B和C的地址是相同的。@hype:这里的关键词是“may”。@Dave Bacher这并不总是正确的。我个人在前一段时间尝试取消引用指向对象的指针时遇到了一个segfault,但指针的类型与函数预期的不同。但是,对象继承自这两种类型。它可能会工作,但并不安全。dynamic_cast
在这里是不合适的,C风格是正确的(尽管形式很糟糕)。根据§5.4/7,C型铸造可调用静态铸造
,其中“-指向非虚拟基类类型的对象、非虚拟基类类型的左值或指向非虚拟基类类型成员的指针可以分别显式转换为指向派生类类型成员的指针、引用或指针。“是的,你是对的,例如,只有当pa
被强制转换为aB*
时才需要动态强制转换。在这种情况下,dynamic\u cast
表达式将是一种表示NULL
的奇特方式。A*不可能是B*,所以它总是会失败。@Potatoswatter:不,那会起作用,因为pa
实际上是一个C*
,而C*
可以转换成B*
。但要想弄清楚这一点,需要一个动态\u cast
。@Skizz:默认情况下,假定基类不是空的。一个新手不需要被他的例子的技术性误导pa==pb
未定义,答案无论如何都不是肯定的是。我请求在pc上有所不同pb
。在devstudio2005中输入问题的代码,我会得到所有具有相同值的指针。这可能是C++标准所说的,在这种情况下,没有虚拟方法,也没有数据成员。OP发布了另一个问题,其中基类确实有成员,因此有一个不同的答案,这或多或少是这个答案。@Skizz:您看到的是所谓的空基类优化,它由所有现代编译器实现,但远远不是必需的;B类{};C类:公共A、公共B{};int main(){C C;C*pc(&C);A*pa(pc);B*pb(pc);printf(“C=0x%08X\nB=0x%08X\nA=0x%08X\n”,pc,pb,pa);}VS2008发布版本的输出C=0x0018FEFF B=0x0018FF00 A=0x0018FEFF如果更改C从A和B继承的顺序,将得到不同的A和B值
(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.