将auto_ptr <Base>转换为auto_ptr <Derived>

Dad*_*dyM 0 c++ casting auto-ptr

请帮我理解以下问题.

看下面的代码示例:

#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;
}
Run Code Online (Sandbox Code Playgroud)

为什么我不被允许这样做:

static_cast<auto_ptr<Circle>>(aS)->GetRadius()
Run Code Online (Sandbox Code Playgroud)

编译器(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
Run Code Online (Sandbox Code Playgroud)

Ste*_*sop 5

auto_ptr在这方面的行为与指针的行为不同.语言中有一些特殊规则允许在派生时Shape*使用static_cast .向下转换并不完全是类型安全的,因为它依赖于用户提供实际指向a的基类子对象的指针值,但标准允许它为方便起见.是"只是"一个库类,并没有等效的转换.Circle*CircleShapeShapeCircleauto_ptr

即使你能做到,也常常会出错.复制时auto_ptr,原始设备将失去对资源的所有权.您static_cast将复制auto_ptr到临时,因此aS将被重置,并且当临时(在表达式结束时)资源将被销毁.在你的例子中没问题,因为它return无论如何都会被破坏,但一般来说你不想复制auto_ptr除了函数调用参数或返回值,以指示从调用者到被调用者的所有权转移,反之亦然.

您可以做的是static_cast<Circle*>(aS.get())->GetRadius(),或者更好地重构代码以避免需要向下转换.如果您知道对象是a Circle,请将其保存在auto_ptr<Circle>[*]中.如果你保持它auto_ptr<Shape>,那么不要依赖它Circle.

[*]或者,如果您的实现提供了它们,可以使用更好的智能指针,例如unique_ptr,scoped_ptrshared_ptr.即使你的实现没有提供它们,也有Boost.