是否可以在从用户那里抽象指针的同时支持多态方法调用?
Is it possible to support polymorphic method calls at the same time as abstracting pointers away from users?
问题
我试图在我的代码中支持某种程度的多态性。我基本上想覆盖 subclasses(Dog
和 Duck
)中的方法 str
,然后使用指向 superclass [=18 的智能指针=] 在另一个 class (AnimalContainer
) 中调用 str
方法。具体来说,我想支持以下 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"
}
此处缺少指针是故意的。我打算将其作为 API 的前端,并希望它尽可能简单。因此,如果可能的话,我想避免让用户自己明确地创建(比如)一个 Dog
指针。换句话说,我想避免让用户做这样的事情:
Dog dog;
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(dog);
AnimalContainer animalContainer(dog_ptr)
std::cout << animalContainer.str() << std::endl;
以上是否可行,如果可行,我需要对以下代码做哪些修改:
代码
#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();
}
};
到目前为止我认为这一行
this->animal_ptr = std::make_unique<Animal>(animal);
是问题,因为 Dog
或 Duck
被分割成 Animal
。然而,另一种选择是在指针 aka
中明确我们想要哪种类型的 Animal
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(Dog())
没有克隆功能,你可以这样做:
class AnimalContainer {
private:
AnimalPtr animal_ptr;
public:
explicit AnimalContainer(const Dog& dog){
this->animal_ptr = std::make_unique<Dog>(dog);
}
// Same for Duck
explicit AnimalContainer(AnimalPtr animal_ptr){
this->animal_ptr = std::move(animal_ptr));
}
std::string str(){ return this->animal_ptr->str(); }
};
或更笼统地说:
class AnimalContainer {
private:
AnimalPtr animal_ptr;
public:
template <typename T>
explicit AnimalContainer(const T& animal){
this->animal_ptr = std::make_unique<T>(animal);
}
explicit AnimalContainer(AnimalPtr animal_ptr){
this->animal_ptr = std::move(animal_ptr));
}
std::string str(){ return this->animal_ptr->str(); }
};
问题
我试图在我的代码中支持某种程度的多态性。我基本上想覆盖 subclasses(Dog
和 Duck
)中的方法 str
,然后使用指向 superclass [=18 的智能指针=] 在另一个 class (AnimalContainer
) 中调用 str
方法。具体来说,我想支持以下 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"
}
此处缺少指针是故意的。我打算将其作为 API 的前端,并希望它尽可能简单。因此,如果可能的话,我想避免让用户自己明确地创建(比如)一个 Dog
指针。换句话说,我想避免让用户做这样的事情:
Dog dog;
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(dog);
AnimalContainer animalContainer(dog_ptr)
std::cout << animalContainer.str() << std::endl;
以上是否可行,如果可行,我需要对以下代码做哪些修改:
代码
#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();
}
};
到目前为止我认为这一行
this->animal_ptr = std::make_unique<Animal>(animal);
是问题,因为 Dog
或 Duck
被分割成 Animal
。然而,另一种选择是在指针 aka
std::unique_ptr<Dog> dog_ptr = std::make_unique<Dog>(Dog())
没有克隆功能,你可以这样做:
class AnimalContainer {
private:
AnimalPtr animal_ptr;
public:
explicit AnimalContainer(const Dog& dog){
this->animal_ptr = std::make_unique<Dog>(dog);
}
// Same for Duck
explicit AnimalContainer(AnimalPtr animal_ptr){
this->animal_ptr = std::move(animal_ptr));
}
std::string str(){ return this->animal_ptr->str(); }
};
或更笼统地说:
class AnimalContainer {
private:
AnimalPtr animal_ptr;
public:
template <typename T>
explicit AnimalContainer(const T& animal){
this->animal_ptr = std::make_unique<T>(animal);
}
explicit AnimalContainer(AnimalPtr animal_ptr){
this->animal_ptr = std::move(animal_ptr));
}
std::string str(){ return this->animal_ptr->str(); }
};