web-dev-qa-db-ja.com

shared_ptr <Base>をshared_ptr <Derived>にダウンキャストしますか?

更新: この例のshared_ptrはBoostのものに似ていますが、shared_polymorphic_downcast(またはdynamic_pointer_castまたはstatic_pointer_cast)をサポートしていません!

参照カウントを失うことなく、派生クラスへの共有ポインターを初期化しようとしています:

struct Base { };
struct Derived : public Base { };
shared_ptr<Base> base(new Base());
shared_ptr<Derived> derived;

// error: invalid conversion from 'Base* const' to 'Derived*'
derived = base;  

ここまでは順調ですね。 C++が暗黙的にBase *をDerived *に変換するとは思っていませんでした。ただし、コードで表現される機能(つまり、ベースポインターをダウンキャストしながら参照カウントを維持する)が必要です。私の最初の考えは、Derivedへの暗黙的な変換が行われるようにBaseにキャスト演算子を提供することでした(ペダントの場合:ダウンキャストが有効であることを確認します、心配しないでください):

struct Base {
  operator Derived* ();
}
// ...
Base::operator Derived* () {
  return down_cast<Derived*>(this);
}

まあ、それは助けにはなりませんでした。コンパイラは私の型キャスト演算子を完全に無視したようです。 shared_ptr割り当てを機能させる方法はありますか?余分なポイント:Base* constは? const Base*わかりましたが、Base* const?この場合、constは何を指しますか?

85
Lajos Nagy

dynamic_pointer_castを使用できます。 std::shared_ptrでサポートされています。

std::shared_ptr<Base> base (new Derived());
std::shared_ptr<Derived> derived =
               std::dynamic_pointer_cast<Derived> (base);

また、基本クラスでキャスト演算子を使用することはお勧めしません。このような暗黙のキャストは、バグやエラーの原因になる可能性があります。

-Update:タイプがポリモーフィックでない場合、std::static_pointer_castを使用できます。

83
Massood Khaari

boost::shared_ptrを使用していると思います... dynamic_pointer_cast またはshared_polymorphic_downcastが必要だと思います。

ただし、これらには多相型が必要です。

Base* constの種類は何ですか? const Base*わかりましたが、Base* const?この場合、constは何を指しますか?

  • const Base *は、定数Baseへの可変ポインターです。
  • Base const *は、定数Baseへの可変ポインターです。
  • Base * constは、可変のBaseへの定数ポインターです。
  • Base const * constは、定数Baseへの定数ポインターです。

最小限の例を次に示します。

struct Base { virtual ~Base() { } };   // dynamic casts require polymorphic types
struct Derived : public Base { };

boost::shared_ptr<Base> base(new Base());
boost::shared_ptr<Derived> derived;
derived = boost::static_pointer_cast<Derived>(base);
derived = boost::dynamic_pointer_cast<Derived>(base);
derived = boost::shared_polymorphic_downcast<Derived>(base);

あなたの例がベース型のインスタンスを作成してキャストするのが意図的であったかどうかはわかりませんが、違いをうまく説明するのに役立ちます。

static_pointer_castは「やるだけ」です。これにより、未定義の動作(Baseに割り当てられて初期化されたメモリを指すDerived*)が発生し、クラッシュまたはさらに悪い結果を引き起こす可能性があります。 baseの参照カウントが増加します。

dynamic_pointer_castはNULLポインターになります。 baseの参照カウントは変更されません。

shared_polymorphic_downcastは静的キャストと同じ結果になりますが、アサーションをトリガーし、むしろ成功したように見え、未定義の動作につながります。 baseの参照カウントが増加します。

(dead link) を参照してください:

static_castを使用するかdynamic_castを使用するかを決定するのが少し難しい場合があり、両方の世界を少し持ってほしいと思うでしょう。 dynamic_castには実行時のオーバーヘッドがあることはよく知られていますが、安全ですが、static_castにはオーバーヘッドがまったくありませんが、静かに失敗する可能性があります。デバッグビルドでshared_dynamic_castを使用し、リリースビルドでshared_static_castを使用できるとしたら、どんなに素晴らしいでしょう。まあ、そのようなものは既に利用可能であり、shared_polymorphic_downcastと呼ばれます。

46
Tim Sylvester

誰かがboost :: shared_ptrでここに来たら...

これは、派生Boostのshared_ptrにダウンキャストする方法です。 DerivedがBaseから継承すると仮定します。

boost::shared_ptr<Base> bS;
bS.reset(new Derived());

boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS);
std::cout << "DerivedSPtr  is: " << std::boolalpha << (dS.get() != 0) << std::endl;

「ベース」クラス/構造体に少なくとも1つの仮想関数があることを確認してください。仮想デストラクタも機能します。

4
Mitendra