C++多继承与指针:派生类指针赋值给基类指针的内存问题咨询
多继承下的指针转换与内存布局问题解答
先看你给出的多继承代码:
class A{}; class B{}; class C: public A, public B{};
以及执行的代码:
C *c = new C; A *a = c; B *b = c; A *a1 = new C; B *b1 = new C;
咱们逐个拆解你的问题:
1. 第一个C类实例会出现什么情况?
new C会在堆上创建一个完整的C类对象,这个对象的内存布局包含了基类A的子对象、基类B的子对象,以及C自身的成员(这里例子里A、B、C都没有自定义成员,所以内存大小是编译器为每个空类分配的最小占位,通常是1字节)。这个实例是完整的,不会有任何部分缺失,直到你用delete释放它之前,都会保持完整状态。
2. 将C指针赋值给A类型指针是否会导致对象切片?
不会!对象切片的场景是当你把派生类对象的值直接赋值给基类对象时才会发生,比如:
C c_obj; A a_obj = c_obj; // 这里才会发生切片:a_obj只保留C中A部分的成员,B和C的部分被丢弃
而你代码里的A* a = c;是指针赋值,本质是让基类指针指向派生类对象中对应的基类子对象的起始地址。对于第一个基类A来说,它的子对象正好是C对象的起始位置,所以a和c的地址是相同的;但如果是赋值给B指针B* b = c;,编译器会自动把指针地址调整到C对象中B子对象的起始位置(也就是C对象地址加上A子对象的大小)。
这种指针转换是安全的,因为指针仍然指向完整的C对象的一部分,并没有丢失任何数据——只是通过基类指针只能访问该基类范围内的成员而已。
3. 编译器如何确定访问的终止偏移?
编译器在编译阶段就已经通过类的继承结构,确定了每个基类子对象在派生类中的内存位置和大小:
- 对于空类A和B,编译器通常会给它们分配1字节的占位空间(C++标准不允许空类大小为0),所以C对象的大小就是2字节(假设没有其他成员)。
- 当你通过A指针访问成员时,编译器知道这个指针指向的是A类型的子对象,所以只会在A子对象的内存范围内(也就是从指针地址开始的1字节)进行访问;同理,B指针访问的是从偏移1字节开始的1字节范围。
- 对于有成员的类,编译器会记录每个成员在类中的偏移量,访问时直接通过指针地址加上偏移量来定位成员,自然不会越界到其他基类的部分。
另外,如果你使用了虚函数,编译器还会通过虚表(vtable)来确保访问的正确性,但在你这个例子里没有虚函数,所以完全是编译时确定的内存布局和偏移。
内容的提问来源于stack exchange,提问作者Dingo
相关产品推荐
相关产品推荐

