0

次の問題を理解するのを手伝ってください。

以下のコード例を見てください。

#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

2 に答える 2

5

auto_ptrこの点では、ポインターと同じように動作しません。言語には、 がから派生するときShape*に static_cast を許可する特別な規則があります。ダウンキャストは、ユーザーが の基本クラス サブオブジェクトを実際に指すポインター値を提供することに依存しているため、完全にタイプ セーフではありませんが、標準では便宜上それを許可しています。は「単なる」ライブラリ クラスであり、同等の変換はありません。Circle*CircleShapeShapeCircleauto_ptr

できたとしても、うまくいかないことがよくあります。をコピーするauto_ptrと、オリジナルはリソースの所有権を失います。を一時的にstatic_castコピーするauto_ptrため、一時的にaS(式の最後に)あるときにリセットされ、リソースが破棄されます。とにかく破棄されるので、あなたの例では問題ありませんが、一般的に言えば、呼び出し元から呼び出し先への所有権の譲渡を示すために、関数呼び出しパラメーターまたは戻り値以外でreturnコピーしたくない、またはその逆。auto_ptr

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

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

于 2011-12-20T10:34:57.007 に答える
3

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

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

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

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

以下のように、参照にキャストすることもできます。

cout << ... << static_cast<Circle&> (*aS).GetRadius () << endl;
于 2011-12-20T10:40:35.330 に答える