I have the following piece of code:
#include <iostream>
class AnimalRepository {
public:
virtual ~AnimalRepository() = default;
virtual auto makeSound() -> void {
std::cout << "Null" << std::endl;
}
};
class CatRepository: public AnimalRepository {
public:
auto makeSound() -> void override {
std::cout << "Meow" << std::endl;
}
};
class DogRepository: public AnimalRepository {
public:
auto makeSound() -> void override {
std::cout << "Woof" << std::endl;
}
};
class Animal {
public:
explicit Animal(const AnimalRepository& repository)
: repository(repository) {
}
auto makeSound() -> void {
return repository.makeSound();
}
protected:
AnimalRepository repository;
};
Animal cat = Animal(CatRepository());
Animal dog = Animal(DogRepository());
int main() {
cat.makeSound();
dog.makeSound();
};
I expected the main function to output the respective cat and dog method override functions, but instead it always returns "Null". I believe this is a case of object slicing, and I'm not quite sure I understand why the reference pointer in the Animal class constructor doesn't avoid this issue.
CodePudding user response:
The slicing is done here: AnimalRepository repository;
. This can't contain a subclass because it is an instance and not a reference or pointer. It is easiest to replace this with a unique smart pointer pointing to a copy of the input.
CodePudding user response:
Or move the whole pattern from dynamic polymorphism to (compile time) static polymorphism
#include <iostream>
class CatBehavior
{
public:
auto makeSound() -> void
{
std::cout << "Meow" << std::endl;
}
};
class DogBehavior
{
public:
auto makeSound() -> void
{
std::cout << "Woof" << std::endl;
}
};
template<typename behavior_t>
class Animal
{
public:
explicit Animal()
{
}
auto makeSound() -> void
{
return m_behavior.makeSound();
}
protected:
behavior_t m_behavior;
};
int main()
{
Animal<CatBehavior> cat;
Animal<DogBehavior> dog;
cat.makeSound();
dog.makeSound();
};