C++类内创建依赖自身对象报错:如何在类A中创建B<typeOne>对象?
问题与解决方案
问题描述
在类A中创建B<typeOne>类型成员myObj时触发不完整类型错误,核心矛盾是myObj的构造依赖已完成初始化的A实例,但原代码中A定义时B<typeOne>的完整类型尚未生效,且A构造过程中直接初始化myObj存在时序问题。
用户疑问:
- 如何正确在
A中创建myObj? - 是否可以通过智能指针先初始化为
nullptr,待A构造完成后再用std::make_shared<B<typeOne>>(*this)构造对象?
原问题代码
#include <iostream> #include <vector> template<typename T> class B; class typeOne; class A { B<typeOne> myObj; public: int myNumber = 10; int myNumberTwo = 20; A(): myObj(*this) {} }; class typeOne { int number_; public: typeOne (const A& myA) : number_(myA.myNumber) {} int number() { return number_; } }; class typeTwo { int number_; public: typeTwo (const A& myA) : number_(myA.myNumberTwo) {} int number() { return number_; } }; template<typename T> class B : public T { const A& myA_; std::vector<int> myVec_; public: explicit B(const A& myA) : T(myA), myA_(myA), myVec_(this->number()) {} }; int main() { A obj1; B<typeOne> obj2(obj1); B<typeTwo> obj3(obj1); std::cout << "here" << std::endl; return 0; }
解决方案
核心原因
原代码报错的直接原因是:A定义时,B<typeOne>的完整类模板实例化尚未完成(B的模板定义在typeOne之后,而A在typeOne之前声明),C++不允许直接声明不完整类型的非指针/非引用成员。此外,A构造函数初始化列表中直接初始化myObj(*this)时,A本身仍处于构造阶段,虽此处成员已初始化,但类型不完整的问题无法规避。
可行方案:智能指针延迟初始化
你提出的智能指针方案完全可行,这是解决此类循环依赖+时序问题的常规手段:
- 修改成员类型:将
A中的B<typeOne> myObj;改为智能指针类型(如std::shared_ptr或std::unique_ptr),前向声明足够支持智能指针的声明。 - 延迟初始化:在
A的构造函数初始化列表中将智能指针设为nullptr,待构造函数体执行时(此时A的所有成员已完成初始化,类型也完整),再通过std::make_shared/std::make_unique创建B<typeOne>对象。
修改后的完整代码
#include <iostream> #include <vector> #include <memory> // 引入智能指针头文件 template<typename T> class B; class typeOne; class A { std::shared_ptr<B<typeOne>> myObj; // 替换为shared_ptr public: int myNumber = 10; int myNumberTwo = 20; A(): myObj(nullptr) // 初始化为空指针 { // 构造函数体中创建对象,此时A已完成成员初始化 myObj = std::make_shared<B<typeOne>>(*this); } }; class typeOne { int number_; public: typeOne (const A& myA) : number_(myA.myNumber) {} int number() { return number_; } }; class typeTwo { int number_; public: typeTwo (const A& myA) : number_(myA.myNumberTwo) {} int number() { return number_; } }; template<typename T> class B : public T { const A& myA_; std::vector<int> myVec_; public: explicit B(const A& myA) : T(myA), myA_(myA), myVec_(this->number()) // T已初始化,可安全调用number() {} }; int main() { A obj1; B<typeOne> obj2(obj1); B<typeTwo> obj3(obj1); std::cout << "here" << std::endl; return 0; }
补充说明
- 若不需要共享所有权,使用
std::unique_ptr替代std::shared_ptr更高效,只需将代码中的std::shared_ptr替换为std::unique_ptr,std::make_shared替换为std::make_unique即可。 - 延迟初始化的本质是将对象的创建时机延后到
A构造完成后,既解决了类型不完整的问题,也确保传递给B的*this是一个已完成初始化的A实例。
内容的提问来源于stack exchange,提问作者user20995624
相关产品推荐
相关产品推荐

