Вопрос:
Предположим, что у нас есть следующие коды. Имеем следующие классы
- Животное как AbstractClass
- Собака и птица, которая является подклассом Animal
- Зоопарк, который держит всех животных
_
class Animal { public: Animal(); void HasWings() = 0; }; class Bird : public Animal { public: Bird() : Animal() {} void HasWings() override { return true; } }; class Dog : public Animal { public: Dog() : Animal() {} void HasWings() override { return false; } }; class Zoo { public: Zoo() {} void AddAnimal(Animal* animal) { _animals.push_back(animal); } … std::vector<Animal*> _animals; }; void myTest() { Zoo myZoo; Bird* bird = new Bird(); Dog* dog = new Dog(); myZoo.AddAnimal(bird); myZoo.AddAnimal(dog); for (auto animal : myZoo._animals) { … } … }
Я надеюсь заменить вектор указателей вектором умных указателей. т.е.
std::vector<std::shared_ptr<Animal>> _animals;
Как изменить код для Zoo и myTest?
Мне сложно обновить код, особенно метод “AddAnimal” в классе Zoo
auto bird = std::make_shared<Bird>(); auto dog = std::make_shared<Dog>(); myZoo.AddAnimal(bird); myZoo.AddAnimal(dog);
птица и собака различного типа
Лучший ответ:
Поведение std::shared_ptr очень похоже на поведение исходного указателя относительно операторов * и -> (фактически, операторы разыменования “пересылаются” внутреннему необработанному указателю, хранящемуся в std::shared_ptr). В частности, вы можете использовать std::shared_ptr для базового класса для виртуальной диспетчеризации по иерархии классов. Например, приведенный ниже код выполняет именно то, что предполагается, а именно вызывает соответствующую функцию во время выполнения:
#include <iostream> #include <memory> #include <vector> struct Base { virtual void f() { std::cout << «Base::f()» << std::endl;} virtual ~Base() = default; // to silence -Wall warnings }; struct Derived: Base { void f() override { std::cout << «Derived::f()» << std::endl;} }; int main() { std::vector<std::shared_ptr<Base>> vsp; // access Derived via shared_ptr to Base auto base = std::make_shared<Base>(); auto derived = std::make_shared<Derived>(); vsp.push_back(base); vsp.push_back(derived); for(auto&& elem: vsp) elem->f(); // virtual dispatch }
Итак, большую часть времени достаточно заменить Animal* на std::shared_ptr<Animal>, и код будет работать. С std::unique_ptr ситуация немного сложнее, так как последний тип типа движения (вы не можете его скопировать), поэтому нужно быть более осторожным.