2009-08-31 14 views
67

更新:この例のshared_ptrはBoostのものと似ていますが、shared_polymorphic_downcast(またはその点についてはdynamic_pointer_castまたはstatic_pointer_cast)をサポートしていません。ダウンキャスティングshared_ptr <Base> to shared_ptr <Derived>?

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

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 *に変換するとは思わなかった。しかし、コードで表現された機能が必要です(つまり、ベースポインタをダウンキャストしている間に参照カウントを維持する)。 、

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

まあ:私が最初に考えたのは派生への暗黙的な変換は、(:私は心配しないで、ダウンキャストが有効であることを確認しますpedantsのための)場所を取ることができるようにBaseのキャスト演算子を提供することでしたそれは助けになりませんでした。コンパイラは私の型キャスト演算子を完全に無視したようです。どのようにshared_ptrの割り当てを行うことができたのでしょうか?余分な点について:どのような種類のタイプBase* constは? const Base*私は理解しますが、Base* const?この場合、constは何を指していますか?

+0

なぜshared_ptr ではなく、shared_ptr が必要ですか? – Bill

+2

オブジェクトをクローンすることなく、BaseにないDerivedの機能にアクセスしたいので(2つの共有ポインタによって参照される1つのオブジェクトが必要です)。ところで、なぜキャスト演算子は動作しませんか? –

答えて

45

私はあなたが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によって初期化されたメモリを指す)が発生し、クラッシュが発生する可能性があります。 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と呼ばれています。

+0

残念ながら、あなたのソリューションは、使用している特定のshared_ptr実装から意図的に除外されたBoost機能に依存しています(理由は問いません)。 constの説明は今はもっと意味がある。 –

+3

'static_cast_tag'と' dynamic_cast_tag'を使って他の 'shared_ptr'コンストラクタを実装するのに手間がかかりません。あなたが 'shared_ptr'の外で行うことはrefcountを管理することができません。 - "完全な"オブジェクト指向設計では、基本型をいつでも使用でき、派生型が何であるかを知らないし気にする必要もありません。おそらく、最初にダウンキャストが必要な理由を再考する必要があるかもしれません。 –

+1

@Tim Sylvester:しかし、C++は「完璧な」OO言語ではありません! :-)ダウンキャストは完全ではないOO言語でその場所を持っています –

55

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を使用することができる、多型ではない場合。誰かがブースト:: shared_ptrので、ここで取得した場合

+3

私は彼が 'std :: shared_ptr'を使用していないことを最初の行から理解しませんでした。しかし、最初の答えのコメントから、私は彼がブーストを使用していないと推測したので、 'std :: shared_ptr'を使用している可能性があります。 –

+0

OK。ごめんなさい。彼は自分がカスタム実装を使用していることを明確にすべきである。 –

3

は...

これは派生ブーストのshared_ptrにダウンキャストすることができる方法です。派生がベースから継承すると仮定します。

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つの仮想機能を持っていることを確認してください。仮想デストラクタも動作します。

関連する問題