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

如何在接收基类对象的函数中创建无切片的std::vector<派生类>

多态集合解决方案:用智能指针容器+Clone模式实现无切片的派生类集合

先梳理下你的现有代码和问题背景:

初始类定义

class Animal{ public:
    virtual void makeSound(){
        std::cout << "I dont know what sound to make." << std::endl;
    }
};

class Dog: public Animal{ public:
    void makeSound() override{
        std::cout << "Woof!" << std::endl;
    }
};

class Cat: public Animal{ public:
    void makeSound() override{
        std::cout << "Meow!" << std::endl;
    }
};

单个对象的无切片拷贝方案

你已经通过添加clone虚函数和虚析构解决了单个多态对象的拷贝问题,这里修正一个小细节:unique_ptr需要用->访问成员函数:

class Animal {
public:
    virtual void makeSound(){
        std::cout << "I dont know what sound to make." << std::endl;
    }
    virtual ~Animal() = default; // 必须添加,确保派生类析构被正确调用
    virtual std::unique_ptr<Animal> clone() const = 0; // 纯虚克隆函数
};

class Dog : public Animal {
public:
    void makeSound() override{
        std::cout << "Woof!" << std::endl;
    }
    std::unique_ptr<Animal> clone() const override {
        return std::make_unique<Dog>(*this);
    }
};

class Cat : public Animal {
public:
    void makeSound() override{
        std::cout << "Meow!" << std::endl;
    }
    std::unique_ptr<Animal> clone() const override {
        return std::make_unique<Cat>(*this);
    }
};

void MakeSound(Animal& animal){
    auto another_animal = animal.clone();
    another_animal->makeSound(); // 这里要改用->,因为unique_ptr是智能指针
}

针对集合需求的解决方案

要创建运行时指定大小的派生类拷贝集合,同时支持自定义派生类、兼容vector的所有标准操作,最直接的方案是使用std::vector<std::unique_ptr<Animal>>作为容器,结合已有的clone方法实现:

核心实现思路

  • 用vector<unique_ptr<Animal>>替代vector<Animal>:智能指针存储基类指针,避免对象切片
  • 依赖clone的多态性:不管是内置的Dog/Cat还是用户自定义的Godzilla,只要实现了clone就能被正确拷贝
  • 完全兼容vector的标准方法:push_back、empty、[]、reserve等操作和普通vector用法一致

示例代码

1. 从原型对象生成指定大小的拷贝集合

// 根据原型对象创建count个拷贝的集合
std::vector<std::unique_ptr<Animal>> createPolymorphicCopies(const Animal& prototype, size_t count) {
    std::vector<std::unique_ptr<Animal>> collection;
    collection.reserve(count); // 预分配内存,提升批量插入的性能
    for (size_t i = 0; i < count; ++i) {
        collection.push_back(prototype.clone());
    }
    return collection;
}

// 测试用例
int main() {
    // 创建5个Dog的拷贝集合
    Dog my_dog;
    auto dog_collection = createPolymorphicCopies(my_dog, 5);
    
    // 遍历集合调用方法
    for (const auto& animal : dog_collection) {
        animal->makeSound(); // 输出5次Woof!
    }

    // 使用vector的标准操作
    if (!dog_collection.empty()) {
        dog_collection[2]->makeSound(); // 访问第三个元素
    }

    // 追加自定义派生类对象(比如Godzilla)
    class Godzilla : public Animal {
    public:
        void makeSound() override {
            std::cout << "Roar!!!" << std::endl;
        }
        std::unique_ptr<Animal> clone() const override {
            return std::make_unique<Godzilla>(*this);
        }
    };
    Godzilla zilla;
    dog_collection.push_back(zilla.clone());
    dog_collection.back()->makeSound(); // 输出Roar!!!

    return 0;
}

2. 拷贝现有多态集合

如果你需要从一个已有的多态集合生成拷贝,同样可以用clone实现:

std::vector<std::unique_ptr<Animal>> copyPolymorphicCollection(const std::vector<std::unique_ptr<Animal>>& source) {
    std::vector<std::unique_ptr<Animal>> dest;
    dest.reserve(source.size());
    for (const auto& animal_ptr : source) {
        dest.push_back(animal_ptr->clone());
    }
    return dest;
}

方案优势

  • 无对象切片:所有派生类对象都以完整形式存储在容器中
  • 扩展性强:用户新增派生类时,只要实现clone方法就能直接加入集合,无需修改容器相关代码
  • 内存安全:unique_ptr自动管理内存,无需手动释放,避免内存泄漏
  • 完全兼容vector操作:所有vector的标准方法都能正常使用,学习成本低

内容的提问来源于stack exchange,提问作者张亦弛

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:57:37