无需存储父类指针,能否从类成员安全访问父类?
关于无父类指针安全访问宿主类的问题
首先直接回答你的核心问题:C++里没有类似this的原生“父类/宿主类指针”——this是指向当前对象实例的指针,而如果你是用组合关系(比如你的代码里Host包含A),默认没有内置的反向引用,必须手动处理,但你代码里硬编码偏移的做法是不安全的,不过我们可以用标准方法修正它。
你的代码存在的安全隐患
你手动写的偏移值8是最大的问题:
- 编译器会根据目标平台的对齐规则给结构体成员添加填充字节,
Host里的uint64_t是8字节,但如果后续添加新成员、调整成员顺序,或者编译器对齐选项变化,这个偏移值会直接失效,导致访问非法内存,触发未定义行为。 - 硬编码偏移完全依赖你对内存布局的猜测,这在跨平台或代码维护时非常脆弱。
安全的解决方法
我们可以用标准库的std::offsetof来自动计算成员在宿主类中的正确偏移,这是C++标准保证的合法操作(只要宿主类是标准布局类型,你的Host和A都满足这个条件)。
修改后的代码如下:
#include <cstddef> #include <cstdint> #include <iostream> template< class Member, class Parent, ptrdiff_t parentToMemberOffset> struct ParentAccess { Parent& parent() { // 通过标准偏移计算获取宿主对象指针,这是标准允许的操作 return *reinterpret_cast<Parent*>( reinterpret_cast<char*>(static_cast<Member*>(this)) - parentToMemberOffset ); } }; // 去掉手动传偏移的模板参数,改用offsetof自动计算 template<class Parent> struct A : ParentAccess<A<Parent>, Parent, offsetof(Parent, a)> { void notifyParent() { this->parent().notify(); } }; struct Host { uint64_t counter = 123; A<Host> a; // 现在无需手动指定偏移 void notify() { counter++; std::cout << "counter is " << counter << std::endl; } }; int main() { Host h; h.a.notifyParent(); // 正确输出:counter is 124 return 0; }
关键说明
- 标准布局类型的要求:
std::offsetof只对标准布局类型有效,这类类型的成员内存布局是连续且可预测的,你的Host和A都符合(没有虚函数、没有非标准布局的基类、成员都是公共访问等)。 - 区别继承与组合:如果是继承关系(比如
A继承自Host),那直接用static_cast<Host*>(this)就能安全转换,编译器会自动处理继承的偏移;但你的场景是组合(Host包含A),属于反向访问,必须通过偏移计算,但用std::offsetof就完全安全。 - 未定义行为的避免:硬编码偏移会导致未定义行为,而用标准方法计算的偏移是编译器保证正确的,所以访问宿主对象是安全的。
内容的提问来源于stack exchange,提问作者hpc64
相关产品推荐
相关产品推荐

