2011-09-05 88 views
8

我已經瀏覽過互聯網,並且這個線程正在尋找一個完整的 回答我所面臨的這種情況。我已經讀過,扔智能指針 不是很聰明。我只是想明白爲什麼 是這樣發生的。我將解釋這種情況。讓我們想象一下這個簡單的 層次:智能指針和異常處理

class Foo 
{ 
public: virtual ~Foo() {} 
}; 

typedef tr1::shared_ptr<Foo> SPFoo; 

class FooInherited: public Foo { }; 

typedef tr1::shared_ptr<FooInherited> SPFooInherited; 

而且我們檢查這個測試代碼:

int main(int argc, char** argv) 
{ 
    try 
    { 
    throw FooInherited(); 
    } 
    catch(const Foo& f) 
    { 
    cout << "Foo& caught!" << endl; 
    } 
    try 
    { 
    throw SPFooInherited(new FooInherited()); 
    } 
    catch(const SPFoo& f) 
    { 
    cout << "SPFoo& caught!" << endl; 
    } 
    return 0; 
} 

一切編譯,但在運行時 執行第二的try-catch不會。有人可以解釋我爲什麼嗎?特別是如果像 這樣的代碼行在運行時工作得很好。

void function(const SPFoo& f) 
{ 
} 

... 

SPFooInherited fi(new FooInherited()); 
function(fi); 

我明白,這個問題是SPFooInherited不會SPFoo(即使FooInherited從富繼承)繼承,但它深深地想知道什麼是編譯器/ RTE從函數調用示例做不同捕捉異常時不能解決問題。是否因爲catch參數與函數調用參數不一樣?爲什麼Foo &工作和SPFoo不?

非常感謝你提前。

Regards, Iker。

回答

13

正如你在你的問題中所說的,SPFooInherited不是SPFoo的子類。這意味着catch(SPFoo const&)將不會捕獲SPFooInherited的實例。另一方面,FooInherited繼承自Foo,因此catch(Foo const&)將捕獲FooInherited的實例。

要理解這一點,您不需要對編譯器或運行時環境有任何特別的理解。它只是語言的一部分。

調用函數的原因是tr1::shared_ptr有一個模板化的非顯式構造函數,允許在函數調用位置進行隱式轉換。

即:tr1::shared_ptr具有下面的構造:

//Note the lack of explicit 
template<class Y> shared_ptr(shared_ptr<Y> const & r); 

這允許shared_ptr從不同的共享指針類型來構造。此構造函數的實現依賴於從FooInherited*Foo*的隱式轉換,以將SPFooInherited中的指針實際存儲到SPFoo中。如果此隱式轉換不存在,則代碼將無法編譯,因此不會出現shared_ptr到不相關類型之間的不安全轉換。

函數調用和卡之間的根本區別是,隱式轉換會發生在函數參數初始化,但一個catch只能匹配單個類型(FooInherited是-A Foo,所以它會匹配)。

3

因爲SPFoo不是SPFooInherited的子類。catch塊只會捕獲其捕獲列表中的東西,或者捕獲列表中的公共子類。 FooInherited確實從Foo開始,因此抓住Foo也可以讓您發現FooInheritedSPFooSPFooInherited是完全不同和無關的類。