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

如何在Repository模式中解决对象切割问题?

问题分析与解决方案

你判断的对象切割问题完全正确,核心原因是:Animal类的repository成员是值类型的AnimalRepository对象,而非指针或引用。

虽然构造函数接收的是const AnimalRepository&(子类对象的引用),但在执行repository(repository)初始化成员时,会把传入的子类对象“切片”——只保留基类AnimalRepository的部分存储到成员变量里。后续调用repository.makeSound()时,自然只会触发基类的方法,而非子类重写的版本。

解决方案一:使用智能指针(推荐)

将Animal类的repository成员改为std::unique_ptr<AnimalRepository>,通过指针指向子类对象,彻底避免切片问题,同时智能指针能自动管理内存:

#include <iostream>
#include <memory>

class AnimalRepository {
public:
    virtual ~AnimalRepository() = default;

    virtual void makeSound() {
        std::cout << "Null" << std::endl;
    }
};

class CatRepository: public AnimalRepository {
public:
    void makeSound() override {
       std::cout << "Meow" << std::endl;
    }
};

class DogRepository: public AnimalRepository {
public:
    void makeSound() override {
        std::cout << "Woof" << std::endl;
    }
};

class Animal {
public:
    explicit Animal(std::unique_ptr<AnimalRepository> repo)
            : repository(std::move(repo)) {
    }

    void makeSound() {
        repository->makeSound();
    }

protected:
    std::unique_ptr<AnimalRepository> repository;
};

int main() {
    Animal cat(std::make_unique<CatRepository>());
    Animal dog(std::make_unique<DogRepository>());
    
    cat.makeSound(); // 输出Meow
    dog.makeSound(); // 输出Woof
};

解决方案二:使用引用(需注意生命周期)

如果坚持用引用,需要确保传入的子类对象生命周期长于Animal对象,比如将子类对象声明为全局变量或在main函数内声明:

#include <iostream>

class AnimalRepository {
public:
    virtual ~AnimalRepository() = default;

    virtual void makeSound() {
        std::cout << "Null" << std::endl;
    }
};

class CatRepository: public AnimalRepository {
public:
    void makeSound() override {
       std::cout << "Meow" << std::endl;
    }
};

class DogRepository: public AnimalRepository {
public:
    void makeSound() override {
        std::cout << "Woof" << std::endl;
    }
};

class Animal {
public:
    explicit Animal(const AnimalRepository& repo)
            : repository(repo) {
    }

    void makeSound() {
        repository.makeSound();
    }

protected:
    const AnimalRepository& repository; // 改为引用类型
};

int main() {
    CatRepository catRepo;
    DogRepository dogRepo;
    
    Animal cat(catRepo);
    Animal dog(dogRepo);
    
    cat.makeSound(); // 输出Meow
    dog.makeSound(); // 输出Woof
};

总结:构造函数的引用参数只是传递对象的方式,要避免切片,必须让Animal类的成员变量以指针或引用的形式指向子类对象,而非存储基类的值对象。

内容的提问来源于stack exchange,提问作者spiklespacklespokle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:00:56