2011-12-20 84 views
0

请帮我理解下面的问题。cast auto_ptr <Base> to 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 2011-12-20 10:44:01

+2

太糟糕了,你不能向下投票评论..我同意你这样一个事实,即std :: auto_ptrs并不总是最好的选择,尽管如果内存管理可以通过包装指针的对象来处理,我并没有发现任何错误。然后开发人员可能会关注他正在解决的实际问题,而不必考虑悬挂指针等。 – 2011-12-20 10:45:28

+0

@sbi我们认为一样..(注意,我没有看到您的意见,因为我没有刷新这个线程时,我没有看到您的意见) – 2011-12-20 10:48:12

回答

5

auto_ptr没有按” t在这方面的表现与指针相同。该语言中有特殊规则允许Shape*为static_cast至Circle*Circle源自Shape。 downcast不是完全类型安全的,因为它依赖于用户提供的指针值实际上指向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>中,则不要依赖它作为Circle。或者,如果您的实施提供了它们,则可以使用更好的智能指针,如unique_ptr,scoped_ptrshared_ptr。即使你的实现不提供它们,也有Boost。

+0

非常清楚。谢谢。但是如果我想在使用auto_ptr时将(static_cast)基础派生到派生,我该怎么办?我知道它可能是错误的,但在这种情况下,我知道指向基类对象的指针确实指向派生类。 – DaddyM 2011-12-20 10:38:28

+0

@DaddyM查看我的帖子,输入时有点缓慢.. – 2011-12-20 10:41:13

+0

我生成的代码与refp的答案完全一样,没有看到它,所以它可能是正确的:-) – 2011-12-20 10:52:34

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; 
+0

谢谢。非常清晰和建设性。 – DaddyM 2011-12-20 11:23:18