如何以更通用的方式转换 unique_ptr 的向量
How to cast vector of unique_ptr in a more generic way
代码:
#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()
。
我想在不将所有权转移给调用者的情况下获得商店中的所有动物,
所以我复制了所有这些并 return 它们。
但是我无法通过下面的方式进行,原因在代码中的注释中说明:
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>>
from/to vector<unique_ptr<Derived>>
,有没有没有 for 循环的方法?
非常感谢任何帮助。
是的,有更好的方法。常见的解决方案 - if/when 你想要一个深拷贝 (就像你当前的 getAllAnimals()
创建的那样) - 是在基础 class 中添加一个虚函数像这样:
virtual std::unique_ptr<Animal> clone() = 0;
然后派生的每个类型 class 都可以实现 clone()
以提供其自身的副本。 getAllAnimals()
然后可以遍历 myAnimals
调用 clone
并将 unique_ptr
推入新容器以 return.
(我假设你的目的是为了其他目的获得一个深拷贝 - 独立于 myAnimals
中的对象。要调用一个函数 应该是 const
就像 whoAmI()
在你不需要深拷贝的对象上...你可以给 AnimalShop()
一个 vector<unique_ptr<Animal>>::const_iterator begin() const { return myAnimals.begin(); }
和类似的 ...end
... 函数,那么你可以写 for (const auto& animal : animalShop) animal->whoAmI();
.)
代码:
#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()
。
我想在不将所有权转移给调用者的情况下获得商店中的所有动物, 所以我复制了所有这些并 return 它们。
但是我无法通过下面的方式进行,原因在代码中的注释中说明:
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>>
from/to vector<unique_ptr<Derived>>
,有没有没有 for 循环的方法?
非常感谢任何帮助。
是的,有更好的方法。常见的解决方案 - if/when 你想要一个深拷贝 (就像你当前的 getAllAnimals()
创建的那样) - 是在基础 class 中添加一个虚函数像这样:
virtual std::unique_ptr<Animal> clone() = 0;
然后派生的每个类型 class 都可以实现 clone()
以提供其自身的副本。 getAllAnimals()
然后可以遍历 myAnimals
调用 clone
并将 unique_ptr
推入新容器以 return.
(我假设你的目的是为了其他目的获得一个深拷贝 - 独立于 myAnimals
中的对象。要调用一个函数 应该是 const
就像 whoAmI()
在你不需要深拷贝的对象上...你可以给 AnimalShop()
一个 vector<unique_ptr<Animal>>::const_iterator begin() const { return myAnimals.begin(); }
和类似的 ...end
... 函数,那么你可以写 for (const auto& animal : animalShop) animal->whoAmI();
.)