C++ unique_ptr存储抽象类Component报无法实例化错误
报错根因
编译器提示cannot instantiate abstract class且错误指向addComponent(Component* component)函数的实现:
void GameObject::addComponent(Component* component) { components.push_back(std::move(std::make_unique<Component>(*component))); }
Component是你定义的抽象类(存在纯虚函数virtual ~Component() = 0),C++语法禁止直接实例化抽象类,而std::make_unique<Component>的逻辑就是在堆上直接构造一个Component对象,自然会触发编译错误。错误定位到std::make_unique的标准库实现写在该文件内,并非标准库本身存在问题。
同时这段代码本身逻辑也存在缺陷:你用vector<std::unique_ptr<Component>>存储组件的核心目的是实现多态,管理Component子类的实例,上述代码会把传入的子类对象解引用后切片拷贝构造基类Component,完全违背了多态设计的初衷。
修复步骤
1. 修正接收原始指针的addComponent逻辑
不要尝试拷贝构造抽象基类,直接接管传入指针的所有权即可,同时补上组件绑定所属GameObject的逻辑:
void GameObject::addComponent(Component* component) { if (!component) return; component->gameObject = this; components.emplace_back(component); }
2. 修复Component类的设计缺陷
你当前的Component类有两个会触发编译/链接错误的问题:
- 写了
Component() = delete;会导致所有子类无法构造基类部分,抽象类的构造函数应该设为protected,禁止外部直接实例化基类,但允许子类调用 - 纯虚析构函数必须提供实现,否则子类析构时会触发链接错误;如果不需要析构做特殊逻辑,直接用默认虚析构即可
修正后的Component类定义参考:
class Component { protected: // 受保护构造函数,仅子类可调用 Component(GameObject* owner = nullptr) : gameObject(owner) {} public: virtual ~Component() = default; virtual std::string getInfo() = 0; // 若要作为抽象基类,建议将核心接口设为纯虚 GameObject* gameObject; };
3. 修复其余代码的已知问题
这些问题不会触发当前的抽象类实例化错误,但不改会导致后续编译/运行异常:
- 补全
GameObject::getInfo()的返回值,当前函数没有return属于未定义行为:std::string GameObject::getInfo() { std::stringstream ss; ss << typeid(*this).name(); for (Uint32 i = 0; i < this->components.size(); i++) { ss << typeid(*components[i]).name() << " " << this->components[i]->getInfo(); } return ss.str(); // 补上返回 } - 修正
getComponents模板函数的错误,当前代码直接对unique_ptr做dynamic_cast是无效的,且遍历未加引用会触发unique_ptr拷贝错误:template<typename T> std::vector<T*> getComponents(){ std::vector<T*> res; for(auto& component : components){ T* ptr = dynamic_cast<T*>(component.get()); if(ptr){ res.push_back(ptr); } } return res; } - 修正
removeComponent的参数设计,当前按值接收unique_ptr要求转移所有权,不符合调用逻辑,改为接收原始指针比对地址即可:// 头文件修改声明 void removeComponent(Component* component); // 源文件实现 void GameObject::removeComponent(Component* component) { for (auto it = components.begin(); it != components.end(); it++) { if (it->get() == component) { components.erase(it); return; } } } - 给接收
unique_ptr的addComponent重载补上组件绑定逻辑:void GameObject::addComponent(std::unique_ptr<Component> component) { if (!component) return; component->gameObject = this; components.push_back(std::move(component)); }
内容的提问来源于stack exchange,提问作者Amigo69
相关产品推荐
相关产品推荐

