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*进行静态转换。downcast 并不完全是类型安全的,因为它依赖于用户提供一个实际上确实指向 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。

于 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 回答