2011-12-20 10 views
0

次の問題を理解してください。以下のコード例でauto_ptrを<Base>からauto_ptrにキャスト<Derived>

ルック:

#include <iostream> 

class Shape { 
public: 
    virtual wchar_t *GetName() { return L"Shape"; } 
}; 
class Circle: public Shape { 
public: 
    wchar_t *GetName() { return L"Circle"; } 
    double GetRadius() { return 100.; } 
}; 

int wmain() { 
    using namespace std; 

    auto_ptr<Shape> aS; 
    auto_ptr<Circle> aC(new Circle); 

    aS = aC; 
    wcout << aS->GetName() << L'\t' << static_cast<auto_ptr<Circle>>(aS)->GetRadius() << endl; 

    return 0; 
} 

私はこれを行うことは許されないのです理由:

static_cast<auto_ptr<Circle>>(aS)->GetRadius() 

コンパイラ(MSVCPP 11):

1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory(911): error C2440: 'initializing' : cannot convert from 'Shape *' to 'Circle *' 
1>   Cast from base to derived requires dynamic_cast or static_cast 
+4

@Truncheon:故意_trolling_ていますか?数ヶ月後、私はこのような気がしませんでした。あなたのコメントは、「私がコメントを落とすことができれば嬉しい」という別のケースです。 – sbi

+2

あまりにもあなたがコメントを下げることはできません。私は、メモリ管理がポインタをラップするオブジェクトによって処理できる場合でも、std :: auto_ptrsが常に最良の代替手段であるとは限りません。開発者は、ポインタなどをぶら下げることを考える代わりに、彼が解決している実際の問題に焦点を当てるかもしれません。 –

+0

@sbi私たちは似ていると思う。(私はこのスレッドをリフレッシュしなかったので、私はあなたのコメントを見たことがなかった) –

答えて

5

auto_ptrは」doesnのこの点でポインタと同じように動作します。 CircleShapeから派生した場合、Shape*Circle*にstatic_castになるようにする言語には特別な規則があります。ダウンキャストは、ユーザがCircleShape基本クラスサブオブジェクトを実際に指すポインタ値を提供することに依存しているため、完全に型安全ではありませんが、標準によって利便性が考慮されています。 auto_ptrはライブラリクラスの「ちょうど」であり、同等の変換はありません。

あなたがそれを行うことができたとしても、しばしば間違っています。 auto_ptrをコピーすると、元のリソースの所有権が失われます。 static_castauto_ptrを一時的にコピーするので、aSはリセットされ、一時的な(式の最後にある)ときにリソースが破棄されます。あなたの例では、とにかくreturnで破壊されるので、一般的には、関数呼び出しパラメータまたは戻り値以外では、auto_ptrをコピーしたくないということで、呼び出し元から呼び出し先への所有権の移転を示す、またはその逆。

代わりに行うことができるのはstatic_cast<Circle*>(aS.get())->GetRadius()です。また、ダウンキャストの必要性を避けるために、コードを再構築することをお勧めします。オブジェクトがCircleであることがわかっている場合は、auto_ptr<Circle> [*]に保管してください。 auto_ptr<Shape>に保存する場合は、Circleであることに頼らないでください。

[*]または、実装で提供されている場合は、unique_ptr,scoped_ptrshared_ptrなどのスマートポインタが優れています。あなたの実装がそれらを提供しないとしても、Boostがあります。

+0

非常に明確です。ありがとう。しかし、auto_ptrを使用してベースをキャスト(static_cast)して派生させたい場合はどうすればよいですか?私はそれが誤っている可能性があることを知っているが、この状況で私は基本クラスのオブジェクトへのポインタが実際に派生したものを指していることを知っている。 – DaddyM

+0

@DaddyM私の投稿を見て、私はそれを入力するときに少し遅かった。 –

+0

私はそれを見ずにrefpの答えとまったく同じコードを生成したので、おそらく正しいだろう:-) –

3

std::auto_ptr<T>はクラスの別のインスタンスで初期化されたときに内部ポインタの所有権を取得するので、確かにそのキャストはしたくありません。

aSはオブジェクトポインタが一時的に所有されているため、オブジェクトはstd::coutステートメントの最後に破棄されます。

代わりに、あなたはおそらく以下のようなものを探しています:

cout << ... << static_cast<Circle*>(aS.get())->GetRadius() << endl; 

あなたはまた、以下のように、基準にそれを唱えてもよい:

cout << ... << static_cast<Circle&> (*aS).GetRadius() << endl; 
+0

ありがとう。非常に明確で建設的です。 – DaddyM

関連する問題