2016-04-29 37 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具有相同的问题,但)