C++分文件定义父子类 父指针/引用引发循环包含解决方案
解决方法
核心逻辑:C++中类内仅持有另一个类的指针/引用时,不需要引入对方的完整头文件,仅做前向声明即可;只有实例化类的完整对象、访问类成员时,才需要引入对应类的完整定义。利用这个规则可以彻底打破头文件循环包含的问题,同时保留分文件存放类定义的要求,具体实现如下:
头文件修改
child.h
不要引入parent.h,仅对Parent类做前向声明,所有需要访问Parent成员的方法只在头文件中声明,不做内联实现:
// file: child.h #pragma once // 前向声明Parent类,不需要引入parent.h class Parent; class Child { private: // 指针/引用都可以,此处以指针为例,引用写法逻辑完全一致 Parent *parent; public: Child(Parent *p) : parent(p) {} // 仅声明需要访问父类的方法,不在头文件内实现 void accessParentMember(); };
parent.h
因为Parent类持有Child类型的完整成员对象,必须获取Child的完整定义才能计算内存布局,因此直接引入child.h即可——此时child.h没有反向引入parent.h,不会触发循环包含:
// file: parent.h #pragma once #include "child.h" class Parent { private: Child child; public: // 可供子类访问的公有成员 int publicAttr = 42; void publicFunc(); Parent() : child(this) {} };
实现文件编写
所有需要访问对方类成员的逻辑,全部放到.cpp实现文件中,在.cpp里再引入需要的头文件:
child.cpp
// file: child.cpp #include "child.h" // 此处才引入parent.h,因为要访问Parent的公有成员,需要类的完整定义 #include "parent.h" void Child::accessParentMember() { // 正常访问父类公有成员 int val = parent->publicAttr; parent->publicFunc(); }
parent.cpp
// file: parent.cpp #include "parent.h" void Parent::publicFunc() { // 父类方法实现逻辑 }
注意事项
- 所有头文件必须加头文件守卫,推荐用
#pragma once,也可以使用传统的#define守卫,避免单文件内重复引入头文件 - 前向声明的类不支持实例化完整对象、不支持直接访问成员,所有涉及调用对方类成员的逻辑,绝对不能在头文件中以内联方式实现,必须放到对应.cpp文件中
- 引用版本的实现不需要调整头文件包含逻辑,仅需要把Child类的成员改为
Parent& parent,构造函数参数改为Child(Parent &p) : parent(p) {},Parent构造函数中初始化child时传child(*this)即可。
内容的提问来源于stack exchange,提问作者vishayp
相关产品推荐
相关产品推荐

