将auto_ptr <base />转换为auto_ptr <derived> </derived>

时间:2011-12-20 10:28:53

标签: 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;
}

为什么我不允许这样做:

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

2 个答案:

答案 0 :(得分:5)

在这方面,

auto_ptr的行为与指针的行为不同。当Shape*派生自Circle*时,语言中有一些特殊规则允许CircleShape。向下转换并不完全是类型安全的,因为它依赖于用户提供的指针值实际上指向Shape的{​​{1}}基类子对象,但标准允许它方便。 Circle“只是”一个库类,没有等效的转换。

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

您可以做的是auto_ptr,或者更好的是重新构建代码以避免需要向下转发。如果您知道自己的对象是static_cast<Circle*>(aS.get())->GetRadius(),请将其保存在Circle [*]中。如果您将其保留在auto_ptr<Circle>中,则不要依赖auto_ptr<Shape>

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

答案 1 :(得分: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;