如何在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
相关产品推荐
相关产品推荐

