The problem
I'm trying to support some degree of polymorphism in my code. I basically want to override a method str
in subclasses (Dog
and Duck
) and then use a smart pointer to the superclass Animal
in another class (AnimalContainer
) to call the str
method. Specifically, I want to support the following API:
int main(){
Duck duck;
Dog dog;
AnimalContainer duckInContainer(duck);
std::cout << duckInContainer.str() << std::endl; // Outputs "None" but should output "Duck"
AnimalContainer dogInContainer(dog);
std::cout << dogInContainer.str() << std::endl; // Outputs "None" but should output "Dog"
}
The lack of pointers here is deliberate. I'm intending this to be a front end of an API and want to make it as simple as possible. Therefore, if possible, I want to avoid making users explicitely create (say) a Dog
pointer themselves. In other words, I'd like to avoid making users do something like this:
Dog dog;
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(dog);
AnimalContainer animalContainer(dog_ptr)
std::cout << animalContainer.str() << std::endl;
Is the above possible and if so, what changes do I need to make to the following code:
The code
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Animal {
public:
Animal() = default;
virtual std::string str() {
return "None";
}
};
class Duck : public Animal {
public:
using Animal::Animal;
std::string str() override {
return "Duck";
}
};
class Dog : public Animal {
public:
using Animal::Animal;
std::string str() override {
return "Dog";
}
};
typedef std::unique_ptr<Animal> AnimalPtr;
class AnimalContainer {
private:
AnimalPtr animal_ptr;
public:
explicit AnimalContainer(const Animal& animal){
this->animal_ptr = std::make_unique<Animal>(animal);
}
explicit AnimalContainer(AnimalPtr animal_ptr){
this->animal_ptr = std::make_unique<Animal>(*animal_ptr);
}
std::string str(){
return this->animal_ptr->str();
}
};
So far I think that this line
this->animal_ptr = std::make_unique<Animal>(animal);
is the issue since the Dog
or Duck
is being sliced to an Animal
. However, the alternative which is being explicit about which type of Animal we want in the pointer aka
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(Dog())