2012-02-21 161 views
3

我已經閱讀了關於在C++中進行轉換的一些信息。從C背景的,使用普通的(type)鑄造是對於像void *但C++常見的有dynamic_castreinterpret_caststatic_cast將指針基類轉換爲指向派生類的指針

問題/問題/問題是應使用哪些上述管型的當基指針和派生指針之間的轉換時。

我們的數據存儲器存儲指向基類的指針(B)。這些函數分配派生的指針(D)。

的代碼示例如下:

class B 
{ int _some_data; } 
class D : public B 
{ int _some_more_data; } 

然後代碼看起來是這樣的:

D *obj = new D; 
obj->_some_data = 1; 
obj->_some_more_data = 2; 
<store obj> 

再後來,當我們訪問數據:

B *objB = <get out data> 
if (objB->_some_data == 1) 
{ D *objD = (D *) objB; <do some processing> } 

現在投我關心的是D *objD = (D *) objB

我們應該使用哪一種?

謝謝。

+0

在這種情況下,dynamic_cast。它將檢查該對象是否可以在運行時轉換爲D *。 – BoBTFish 2012-02-21 08:25:49

+3

@BoBTFish'dynamic_cast'只適用於多態類型。 – 2012-02-21 08:30:32

回答

3

對於您瞭解但編譯器不知道的相關類型,請使用static_cast

但在你的情況下,你根本不應該施放。

你編寫

我們的數據存儲裝置存儲一個指向基類(B)。函數分配派生的指針(D)。

這就是扔掉信息,這不是一個好主意。有人意識到這不是一個好主意,實際上它不能工作,因此試圖在B::_some_data的值中動態地保存該類型信息。總的影響:丟棄C++支持來處理該類型的信息,並用一個非常脆弱和髒的本土解決方案。

爲了充分利用C++的支持,使B中的多態類,即具有至少一個virtual構件:

struct B { virtual ~B() {} }; 

我刪除數據成員_some_data因爲顯然它唯一的目的是要跟蹤的動態類型,現在C++支持在實際中通過對象中的所謂「vtable指針」來實現這一點。對象的總大小可能相同。但是,吸引力和純粹的醜陋卻減少了一些數量級。 ;-)

然後,

struct D 
    : B 
{ 
    int some_more_data_; 
    D(int v): some_more_data_(v) {} 
}; 

,然後用多態類,你的處理代碼可以使用一個安全的dynamic_cast,如下:

B* const objB = getOutData(); 
if(D* const objD = dynamic_cast<D*>(objB)) 
{ 
    // do some processing using objD 
} 

現在本手冊動態類型檢查仍然非常骯髒,反映了非OO系統架構。通過對象定位,數據不是檢查給定數據的操作,而是有效地包含指向適當專用操作的指針。但我認爲最好一次採取一步,作爲上述第一步:擺脫吸收脆弱的臭蟲的本土動態類型檢查方案,並使用相對乾淨的超級爽快新鮮美觀的好看等C++的支持。 :-)

+0

謝謝 - _some_data被用來傳達比以上更多的信息,但我明白了。然而,我並沒有遵循'使用對象概念,而不是操作來檢查它們已經給出了什麼類型的數據,數據有效地包含指向適當的專門操作的指針。這是否意味着基類包含所有可能操作的虛函數?謝謝。 – user626201 2012-02-21 09:07:27

+1

不,它不需要「包含所有可能的操作的虛擬功能」。明顯的需求是設計氣味,但是,當這種明顯的需求彈出時,什麼是實用的解決方案?那麼,這是一個非常常見的問題,它應該是一個常見問題解答,答案是「訪問者模式」。在這裏解釋太多,但實際上,您會向訪問者發送知道類型的代碼。然後,該代碼可以回訪專門處理給定類型的訪問者部分。 – 2012-02-21 09:10:20

+0

謝謝 - 我會查找模式 - 從來沒有聽說過它。 – user626201 2012-02-21 09:29:38

0

在這種情況下,您應該使用dynamic_cast

+0

+1以對抗無法解釋的ungood downvote。 – 2012-02-21 08:28:42

+1

@ Cheersandhth.-Alf'dynamic_cast'不起作用,因爲他的類不是多態的。 – 2012-02-21 08:29:27

+0

@乾杯和hth。 - Alf,謝謝 – Sergey 2012-02-21 08:32:07

6

在這種情況下,沒有演員是真正安全的。

最安全的將是dynamic_cast,但您的對象不是多態的,所以它不適用於此。但是你應該考慮至少有一個析構函數,因爲我可以看到你計劃擴展類。

static_cast並不安全,因爲這個msdn頁指出:

class B {}; 

class D : public B {}; 

void f(B* pb, D* pd) { 
    D* pd2 = static_cast<D*>(pb); // not safe, pb may 
            // point to just B 

    B* pb2 = static_cast<B*>(pd); // safe conversion 
} 

reinterpret_cast也沒有檢查,所以不要依賴它。

另外,投射到派生類的指針至少是一種代碼味道,如果你需要這樣做,它99%肯定你有一個有缺陷的設計。

+0

你爲什麼說他的物體不是多態的?它們來自對方...我會同意缺少虛擬析構函數tho。 – RedX 2012-02-21 08:30:06

+1

'static_cast'將是合法的,並且做他想做的事(但我同意你的分析,唯一的好的解決方案是使對象變爲多態並使用'dynamic_cast')。 – 2012-02-21 08:30:28

+0

@RedX在C++中,如果至少有一個虛擬函數,則只能將對象類型視爲多態。繼承是一種實現技術,可以用於不同的目的,而不僅僅是多態。 (我認爲任何人都不會認爲迭代器是多態的,只是因爲它來自'std :: iterator'。) – 2012-02-21 08:32:26

相關問題