You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:54:21