C++中两个对象共享同一地址的处理及零大小子对象操作问题
基类子对象与派生类对象地址的问题
你给出的代码是符合空基类优化规则的典型场景:
struct A{}; struct B:A{}; int main(){A a; B b;}
首先可以明确的是:b和它的A类型基类子对象确实共享同一个内存地址,这个结论完全符合C++标准规定:
- 独立的空类完整对象(例如代码中的
a)大小为1字节,是为了保证不同独立对象拥有唯一的内存地址,满足C++对象模型的基本要求。 - 标准明确规定没有非静态数据成员的标准布局类的基类子对象大小可以为0,你的代码中
struct B符合标准布局要求,因此它的A类型基类子对象没有占用额外内存,最终B类型的完整对象b大小也为1字节。 - 零大小子对象允许使用所属完整对象的任意字节地址,
b本身仅有1字节存储空间,因此基类子对象必然和b自身共享同一个起始地址。
零大小子对象的指针处理规则
指向零大小子对象的指针遵循常规C++指针规则,仅在操作范围上有少量约束:
- 指针转换逻辑完全正常:你可以合法地将
B*类型的指针隐式转换为A*类型,得到的就是指向零大小基类子对象的指针,该指针的数值和原始B*指针完全相同。 - 支持所有无内存读写的合法操作:你可以对这类指针执行取地址、类型转换、相等性比较操作,也可以通过指针调用基类的成员函数——空基类一般仅包含成员函数,没有非静态数据成员,调用过程不需要访问对象的存储内容,不会出现越界访问问题。
- 禁止执行内存读写类操作:不要尝试对零大小子对象的指针做解引用读写、内存拷贝这类涉及存储内容读写的操作,这类行为属于未定义行为。
补充:实际开发中空基类的使用非常普遍,比如STL中的迭代器标记类、无状态策略类都是通过空基类实现的,零大小子对象的指针处理逻辑已经被编译器做了完善兼容,只要不执行非法的内存读写操作就不会出现问题。
内容的提问来源于stack exchange,提问作者user15071942
相关产品推荐
相关产品推荐

