2011-12-20 82 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