ポインタ(およびそのトラップ)の使用については説明しました。動的メモリ割り当てを使用せずにポリモーフィズムを使用する方法を紹介します。おそらく、私がそれについて考えることすら異端者であることを証明します。
まず、コンパイルされるようにパッチを適用した元のコードを見てみましょう。
void foo(bool const cond) {
Base* b = 0;
if (cond) { b = new Derived1(); }
else { b = new Derived2(); }
b->func1();
delete b; // do not forget to release acquired memory
}
virtual
のデストラクタがあると仮定すると、これは正常に機能しますBase
。
プログラマーの進化における次の論理的なステップは、スマートポインターを使用して、delete
(delete
初心者および専門家のライブラリ作成者のみが使用する)書き込みを回避することです。
void foo(bool const cond) {
std::unique_ptr<Base> b;
if (cond) { b.reset(new Derived1()); }
else { b.reset(new Derived2()); }
b->func1();
}
もちろん、それでもvirtual
デストラクタが必要です。Base
この関数が2つのことを行うことを理解しましょう。
- 条件を与えられたクラスを選択してください
- 生成されたインスタンスでいくつかの作業を行います
たとえば、ビルド作業を抽出することで、それを分解できます。
std::unique_ptr<Base> build(bool const cond) {
if (cond) { return { new Derived1() }; }
return { new Derived2() };
}
void foo(bool const cond) {
std::unique_ptr<Base> b = build(cond);
b->func1();
}
これはほとんどの人がしていることです。
ビルドを分離する代わりに、実際の作業を分離できる別の可能性があると私は主張します。
void dowork(Base& b) { b.func1(); /* and perhaps other things */ }
void foo(bool const cond) {
std::unique_ptr<Base> b(cond ? new Derived1() : new Derived2());
work(*b);
}
実際にさらに一歩進めることができます。
void foo(bool const cond) {
if (cond) {
Derived1 d;
work(d);
} else {
Derived2 d;
work(d);
}
}
ポリモーフィズムは動的メモリ割り当てを必要としません。
そして、あなたはこの最後の例の何が楽しいか知っています:
- C++11の移動セマンティクスがなくても完全に正常に機能します
virtual
デストラクタが必要ありませんBase