2016-04-29 76 views
4

的參考這是不是C++ 11空調風格的演員和C++的static_cast到指針

我感興趣的是微軟的 CMapStringToOb::GetNextAssoc,第3參數,它具有以下定義:

void GetNextAssoc(
    POSITION& rNextPosition, 
    CString& rKey, 
    CObject*& rValue 
) const; 

然後我有以下簡單的測試代碼:兩個好例子和一個編譯器錯誤的例子。

class CMyObject : public CObject //in order to use CMapStringToOb 
{ 
public: 
    CMyObject(CString name_) 
     :name(name_) 
    { 
    } 

    void SayHello() 
    { 
     TRACE(_T("hello") + name); 
    } 
    CString name; 
}; 

void main() 
{ 
    CMapStringToOb myMap; 
    myMap.SetAt(_T("a"), new CMyObject(_T("aaa"))); 
    myMap.SetAt(_T("b"), new CMyObject(_T("bbb"))); 
    myMap.SetAt(_T("c"), new CMyObject(_T("ccc"))); 

    //good case 1 
    POSITION pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CMyObject* pMine = NULL; 
     myMap.GetNextAssoc(pos, s, (CObject*&)pMine); 
     if(pMine) 
     { 
      pMine->SayHello(); 
     } 
    } 

    //good case 2 
    pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CObject* pObject = NULL; 
     myMap.GetNextAssoc(pos, s, pObject); 
     if(pObject) 
     { 
      CMyObject* pMine = static_cast<CMyObject*>(pObject); 
      pMine->SayHello(); 
     } 
    } 

    //bad case: 
    //can not compile 
    // error C2440: 'static_cast' : cannot convert from 'CMyObject *' to 'CObject *&'  
    //  static_cast and safe_cast to reference can only be used for valid initializations or for lvalue casts between related classes 

    pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CMyObject* pMine = NULL; 
     myMap.GetNextAssoc(pos, s, static_cast<CObject*&>(pMine)); //compile error 
     if(pMine) 
     { 
      pMine->SayHello(); 
     } 
    } 
} 

所有我試圖做的是找到一種正確的方式來取代C風格鑄造到C++風格鑄造在這種情況下。

this閱讀,它提到:

Ç管型是使用(類型)的對象或類型(對象)的類型轉換。投 A C式被定義爲其中第一個成功以下的:

const_cast 
static_cast (though ignoring access restrictions) 
static_cast (see above), then const_cast 
reinterpret_cast 
reinterpret_cast, then const_cast 

Q1的:以上列表中缺少任何東西(例如,用於右值)?

Q2:在這種情況下,將C風格轉換爲C++風格轉換的正確方法是什麼? (好的情況2有效,但是,有沒有更簡潔的一個?)

問題3:C風格如何爲rValue執行操作? (換句話說,請解釋爲什麼好的情況1工作)

+0

您需要使用'reinterpret_cast'作爲引用和指針類型。 – paddy

+0

@paddy:「參考和指針」是指「*&」?換句話說,下面的兩個陳述是否一致? S1:「你需要使用reinterpret_cast作爲引用類型。」 S2:「你需要爲指針類型使用reinterpret_cast。」 – milesma

+0

是的。你有什麼是對指針類型的引用。我只是想爲那些引用或指針使用'reinterpret_cast'。 – paddy

回答

3

您不能static_cast引用(或指針)到「不相關的類型」之間。雖然你可以從CMyObject*static_castCObject*,但這不是你在這裏做的。這裏你試圖將一個指針的引用轉換爲對另一個指針的引用。而這兩種指針類型不具有繼承關係。

我喜歡你的「好例子2」代碼 - 我就是這樣運行的。

有關指針類型的非關聯的詳細信息,請看這裏:static_cast and reference to pointers

+0

太棒了!我被*簽名欺騙了,我重新看了這個**,然後它變得很明顯。順便說一句,我也發佈了這個問題的答案來解釋這一點。謝謝! – milesma

+0

斷言之前,指針指向特定類型通常是一個好主意。 MFC的'CObject'實現[CObject :: IsKindOf](https://msdn.microsoft.com/en-us/library/b7tsah76.aspx)函數。在'static_cast'之前添加'ASSERT(pObject-> IsKindOf(RUNTIME_CLASS(CMyObject)));'是達到此目的的一種方法。 – IInspectable

1

正確的方法編寫的代碼是使用std::map<>。即使您堅持主要保留現有代碼,也可以考慮修復GetNextAssoc()的界面以返回指針。爲了做到這一點,你可以簡單地添加函數的重載:

CObject* GetNextAssoc(
    POSITION& rNextPosition, 
    CString& rKey, 
) const { 
    CObject* res = 0; 
    GetNextAssoc(rNextPosition, rKey, res); 
    return res; 
} 

更有甚者,你可以模板功能進行轉換爲目標類型存在。此外,您可以使用dynamic_cast,因爲正式使用,容器商店CObjects,它們可能有各種不同的類型。

現在,爲什麼我會部分忽略你的問題?原因是MFC不遵循現代編碼風格,在某些情況下,他們只是做一些令人不悅的事情。這種行爲有很多理由,但最重要的是年齡(不知道更好,沒有適當的模板支持)和兼容性問題(現在無法改變)。這不是重複這些錯誤的理由。

+1

GetNextAssoc的包裝函數的想法不錯。您可能需要通過返回CObject * – milesma

+0

來修復簽名謝謝@ milesma修復了返回類型。 –

1

約翰Zwinck的啓發,我會從不同的角度:

static_cast<CObject*>(pMine) 

成功因爲類型 「CMyObject」 從類型 「CObject的」 一概而論;實際上,這是隱含的;

static_cast<CMyObject*>(pObject) 

成功因爲類型 「CMyObject」 從類型 「CObject的」 一概而論;

static_cast<CObject**>(&pMine) 

失敗因爲類型 「CMyObject *」 不從類型概括 「CObject的*」;

reinterpret_cast<CObject**>(&pMine) 

在因爲 「reinterpret_cast的」 編譯時成功; 運行時間怎麼樣?

讓我們把可能出現的新的實現的假設:

void CMapStringToOb::GetNextAssoc(
     POSITION& rNextPosition, 
     CString& rKey, 
     CObject** ppValue) 
{ 
    *ppValue = (the pointer at the current position, point to an instance of "CMyObject"); 
} 

所以通過調用這個函數:

GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine)) 

的結果是,「pMine」指向的實例「 CMyObject「;

因此運行時間是SAFE

然而,如果把它插入由鍵值(注:CYourObject無期廣義關係CMyObject)

myMap.SetAt(_T("a"), new CYourObject(_T("aaa"))); 

,並把它弄出來的

GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine)); 

編譯的時候還是會成功,但是,pMine現在指向「CYourObject」,它將在運行時處爲未定義的行爲。 (雖然static_cast具有相同的問題,但)