C样式转换和C ++ static_cast引用指针

时间:2016-04-29 02:02:16

标签: c++ casting mfc

这不是C ++ 11

我对微软的第三个参数感兴趣 CMapStringToOb::GetNextAssoc,其定义如下:

 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读来,它提到:

  

C强制转换是使用(类型)对象或类型(对象)进行强制转换。一个C风格的演员   被定义为以下第一个成功:

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

Q1:以上列表是否缺少任何内容(例如rValue)?

Q2:在这种情况下,将C样式转换为C ++样式的正确方法是什么? (好的案例2有效,但是,有更简洁的吗?)

问题3:C Style为rValue做了什么? (换句话说,请解释为什么好的案例1有效)

3 个答案:

答案 0 :(得分:3)

在“无关类型”的引用(或指针)之间不能static_cast。虽然您可以从static_castCMyObject* CObject*,但这不是您在这里所做的。在这里,您尝试将指针的引用转换为对另一个指针的引用。并且这两种指针类型没有继承关系。

我喜欢你的“好案例2”代码 - 我会用它运行。

有关指针类型不相关的更多详细信息,请参阅此处:static_cast and reference to pointers

答案 1 :(得分:1)

编写该代码的正确方法是使用std::map<>。即使您坚持主要保留现有代码,也可以考虑修复GetNextAssoc()的接口以返回指针。为此,您可以简单地添加该函数的重载:

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

更重要的是,您可以模拟该功能并在那里转换为目标类型。此外,您可以使用dynamic_cast,这应该被使用,因为正式地,容器存储CObjects并且它们可以具有各种不同的类型。

现在,为什么我部分忽略了你的问题?原因是MFC不遵循现代编码风格,在某些情况下,他们只是做一些不赞成的事情。对于这种行为有很多理由,但最重要的是它是年龄(没有更好的知识,没有适当的模板支持)和兼容性问题(现在无法改变)。但这并不是重复这些错误的理由。

答案 2 :(得分:1)

受John 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”,它将在运行时 UNDEFINED BEAVAVIOR 。 (但是static_cast有同样的问题)