You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

指针地址是否会在特定情况下改变?派生类对象存储相关问询

关于C++指针与继承的三个问题解答

让我逐个拆解你的问题,结合C++的内存模型和继承机制来解释清楚:

指针的地址是否会在特定情况下发生改变?

首先得明确两个容易混淆的概念:指针变量自身的内存地址,和指针指向的目标地址。

  • 指针变量自身的地址:在它的生命周期内是固定不变的。比如栈上的局部指针,从创建到出作用域销毁,它在栈中的位置不会变动;堆上分配的指针(比如int** ptr = new int*;),这个ptr的地址也会一直保持到你delete它。只有当指针变量被销毁(比如局部变量离开作用域),它的地址才会失效,但这不是“改变”,而是该地址不再对应有效的变量了。
  • 指针指向的目标地址:这个是可以主动或被动改变的。比如你给指针重新赋值ptr = &another_var;,指针指向的地址就变成了另一个变量的地址;再比如用realloc重新分配内存时,原指针指向的旧内存会被释放,指针会被更新为新内存块的地址。另外还有一种被动情况:当vector这类容器扩容时,内部元素会被移动到新的内存区域,原来指向这些元素的指针就会失效(指向的还是旧地址,但该内存已经不属于容器了),这也可以理解为“指向的地址不再有效”。

存储基类指针的vector存入派生类指针,地址是否会偏移?

这个问题核心是C++继承中的基类指针指向派生类对象的地址调整规则,和vector的存储无关——vector只是原样保存指针的值而已。

  • 单继承场景:派生类对象的起始地址和它内部的基类子对象起始地址完全一致。比如class Derived : public Base {};,当你把Derived*类型的指针存入vector<Base*>时,指针的值(也就是指向的地址)不会有任何调整,直接就是派生类对象的起始地址。派生类新增的数据成员都在基类子对象的内存之后,不会影响基类指针的指向地址。
  • 多重继承场景:如果派生类继承了多个基类,那么除了第一个基类子对象的起始地址和派生类对象地址相同外,其他基类子对象的地址会有偏移。比如class Derived : public Base1, public Base2 {};,当你把Derived*转换成Base2*时,指针的值会比原Derived*的值多出sizeof(Base1)的偏移量。这时候如果把这个Base2*存入vector<Base2*>,指针的值已经是调整后的偏移地址了;如果存入vector<Base1*>,则指针值和派生类对象地址一致。

new基类数组存放派生类对象,编译器如何处理地址?

这里要分两种完全不同的情况,本质是对象切片的问题:

  1. 直接创建基类对象数组
    比如你写Base* arr = new Base[3];,数组里的每个元素都是Base类型的对象。如果尝试把派生类对象赋值给数组元素(比如arr[0] = Derived();),编译器会执行对象切片:只把派生类对象中属于Base的部分拷贝到数组的Base对象中,派生类新增的成员会被直接丢弃。此时数组的起始地址就是第一个Base对象的地址,后续每个元素按sizeof(Base)的大小依次偏移,不存在“起始地址变更”的情况——因为你根本没存储完整的派生类对象。

  2. 创建基类指针数组
    比如Base** arr = new Base*[3];,数组里存储的是指向Base的指针。你可以把new Derived()的指针赋值给数组元素(arr[0] = new Derived();),此时每个指针指向的是完整的派生类对象。地址的处理和第二个问题一致:单继承下指针值等于派生类对象的起始地址;多重继承下如果是第二个及以后的基类指针,会有地址偏移。数组本身的起始地址是固定的,每个指针元素的地址按sizeof(Base*)的大小依次偏移。

内容的提问来源于stack exchange,提问作者asmmo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:13:52