次のコードがあるとします。以下のクラスがあります
_
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のコードをどのように変更しますか?コード、特にZooクラスのメソッド「AddAnimal」の更新が難しいと感じています
auto bird = std::make_shared<Bird>();
auto dog = std::make_shared<Dog>();
myZoo.AddAnimal(bird);
myZoo.AddAnimal(dog);
鳥と犬はタイプが違います
std::shared_ptr
の動作は、*
および->
演算子に関して、rawポインターの動作と非常に似ています(実際、逆参照演算子は、格納されている内部rawポインターに「転送」されます)。 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
は移動専用タイプ(コピーできない)であるため、状況は少し複雑になります。したがって、より注意する必要があります。