c++ - 如何以更通用的方式转换 unique_ptr 的 vector

标签 c++ vector polymorphism unique-ptr

编码:

#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class Animal
{
    protected:
        // protected constructor, so it should be constructed from the derived class
        Animal(int animalProp):
            myAnimalProp(animalProp)
        {
        }
        
        Animal(const Animal &animal):
            myAnimalProp(animal.myAnimalProp)
        {
        }
        
        Animal(Animal &&animal):
            myAnimalProp(animal.myAnimalProp)
        {
        }
        
    public:
        virtual void whoAmI() const
        {
            cout << "Animal" << endl;
        }
        
        virtual void setAnimalProp(int val)
        {
            myAnimalProp = val;
        }
        
        virtual int getAnimalProp() const
        {
            return myAnimalProp;
        }
        
    protected:
        int myAnimalProp = 0;
};

class Dog: public Animal
{
    public:
        Dog(int animalProp, int dogProp):
            myDogProp(dogProp),
            Animal(animalProp)
        {
        }
        
        Dog(const Dog &dog):
            myDogProp(dog.myDogProp),
            Animal(dog)
        {
        }
        
        Dog(Dog &&dog):
            myDogProp(dog.myDogProp),
            Animal(move(dog))
        {
        }
    
        virtual void whoAmI() const override
        {
            cout << "Dog" << endl;
        }
        
        virtual void setAnimalProp(int val) override
        {
            myAnimalProp = val + 10;
        }
        
        virtual int getAnimalProp() const override
        {
            return myAnimalProp;
        }
        
        void setDogProp(int val)
        {
            myDogProp = val;
        }
        
        int getDogProp() const
        {
            return myDogProp;
        }
        
    private:
        int myDogProp = 10;
};

class Cat: public Animal
{
    public:
        Cat(int animalProp, int catProp):
            myCatProp(catProp),
            Animal(animalProp)
        {
        }
        
        Cat(const Cat &cat):
            myCatProp(cat.myCatProp),
            Animal(cat)
        {
        }
        
        Cat(Cat &&cat):
            myCatProp(cat.myCatProp),
            Animal(move(cat))
        {
        }
    
        virtual void whoAmI() const override
        {
            cout << "Cat" << endl;
        }
        
        virtual void setAnimalProp(int val) override
        {
            myAnimalProp = val + 20;
        }
        
        virtual int getAnimalProp() const override
        {
            return myAnimalProp;
        }
        
        void setCatProp(int val)
        {
            myCatProp = val;
        }
        
        int getCatProp() const
        {
            return myCatProp;
        }
        
    private:
        int myCatProp = 20;
};

class AnimalShop
{
    public:
        AnimalShop()
        {
            myAnimals.push_back(make_unique<Dog>(1, 11));
            myAnimals.push_back(make_unique<Cat>(1, 21));
            myAnimals.push_back(make_unique<Dog>(1, 12));
        }
        
        vector<unique_ptr<Animal>> getAllAnimals()
        {
            vector<unique_ptr<Animal>> animals;
            
            for (const unique_ptr<Animal>& animal: myAnimals)
            {
                // I cannot do so
                // because it will try to call the copy constructor of Animal
                // and I want to call the copy constructor of derived class
                // not to mention the copy constructor is in protected scope
                
                //animals.push_back(make_unique<Animal>(*animal));
                
                if (const Dog *dog = dynamic_cast<const Dog *>(animal.get()))
                {
                    animals.push_back(make_unique<Dog>(*dog));
                }
                else if (const Cat *cat = dynamic_cast<const Cat *>(animal.get()))
                {
                    animals.push_back(make_unique<Cat>(*cat));
                }
            }
            
            return animals;
        }
        
    private:
        vector<unique_ptr<Animal>> myAnimals;
};

int main()
{
    cout << "Starting" << endl;
    
    AnimalShop animalShop;
    vector<unique_ptr<Animal>> animals_000 = animalShop.getAllAnimals();
    for (const unique_ptr<Animal> &animal: animals_000)
    {
        animal->whoAmI();
        animal->setAnimalProp(2);
        cout << "Animal Prop: " << animal->getAnimalProp() << endl;
    }
    
    vector<unique_ptr<Animal>> animals_001 = animalShop.getAllAnimals();
    for (const unique_ptr<Animal> &animal: animals_001)
    {
        animal->whoAmI();
        cout << "Animal Prop: " << animal->getAnimalProp() << endl;
    }
   
    cout << "Ending" << endl; 
   
    return 0;
}
事实上,我的问题是关于函数 AnimalShop::getAllAnimals() .
我想在不将所有权转让给来电者的情况下获得商店中的所有动物,
所以我将它们全部复制并返回。
但是我无法按照代码中注释中所述的原因以以下方式执行此操作:
animals.push_back(make_unique<Animal>(*animal));
相反,我需要用更冗长的方式来做:
if (const Dog *dog = dynamic_cast<const Dog *>(animal.get()))
{
    animals.push_back(make_unique<Dog>(*dog));
}
else if (const Cat *cat = dynamic_cast<const Cat *>(animal.get()))
{
    animals.push_back(make_unique<Cat>(*cat));
}
有没有更好的方法来做到这一点?
另一个问题,用于类型转换 vector<unique_ptr<Base>>从/到 vector<unique_ptr<Derived>> , 有没有办法在没有 for 循环的情况下做到这一点?
任何帮助都受到高度赞赏。

最佳答案

是的,有更好的方法。常见的解决方案 - 如果/当你想要一个深层拷贝(比如你当前的 getAllAnimals() 创建) - 是在基类中添加一个虚拟函数,如下所示:

virtual std::unique_ptr<Animal> clone() = 0;
那么每种派生类都可以实现clone()提供其自身的拷贝。 getAllAnimals()然后可以循环遍历 myAnimals调用 clone并推送 unique_ptr s 放入一个新的容器中返回。
(我假设您的目的是获得深层拷贝 - 独立于 myAnimals 中的对象,用于其他目的。在不需要的对象上调用应该是 const 的函数,例如 whoAmI()一个深拷贝...你可以给 AnimalShop() 一个 vector<unique_ptr<Animal>>::const_iterator begin() const { return myAnimals.begin(); } 和类似的 ... end ... 函数,然后你可以写 for (const auto& animal : animalShop) animal->whoAmI(); 。)

关于c++ - 如何以更通用的方式转换 unique_ptr 的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68645108/

相关文章:

c++ - Qt 的 foreach 中的第二项是否仅评估一次?

c++ - 特拉维斯 CI : clang deduces copy constructor when it should deduce move constructor

java - 使用 Jackson 对 JSON 文件进行多态反序列化

c++ - 多态性和成员函数指针是如何工作的?

java - REST API 和多态性

c++ - 在 C++ 中对数字数组进行排序时,是否必须将字符串转换为 double ?

c++ - 简单的 C++ 函数包含失败

c++ - 错误 : passing ‘const Vector<int>’ as ‘this’ argument of . .. 丢弃限定符 [-fpermissive]

wpf - DxScene 是 "WPF for Delphi"吗?有人用过吗?

ios - 我可以像快速调整常规 View 一样调整贝塞尔路径的大小吗?