简体   繁体   English

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

[英]C Style cast and C++ static_cast to reference of pointer

This is NOT C++11 这不是C ++ 11

I'm interested in the 3rd parameter of Microsoft's CMapStringToOb::GetNextAssoc , which has following definition: 我对Microsoft的CMapStringToOb :: GetNextAssoc的第三个参数感兴趣 ,它具有以下定义:

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

Then I've got following easy code for testing: two good cases and one case with compiler error. 然后我有以下简单的测试代码:两个好的案例和一个编译错误的案例。

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();
        }
    }   
}

All I was trying to do is find an proper way to replace the C style casting to C++ style cast in this case. 在这种情况下,我所要做的就是找到一种将C风格的转换替换为C ++样式的正确方法。

Reading from this , it mentioned: 从阅读这个 ,它提到:

C casts are casts using (type)object or type(object). C强制转换是使用(类型)对象或类型(对象)进行强制转换。 A C-style cast is defined as the first of the following which succeeds: C样式强制转换定义为以下第一个成功:

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

Q1: Was the above list missing anything (eg for rValue)? Q1:以上列表是否缺少任何内容(例如rValue)?

Q2: What's the proper way of translate C style cast to C++ style cast in this case ? Q2:在这种情况下,将C样式转换为C ++样式转换的正确方法是什么? (good case 2 works, but, is there a more concise one?) (好的案例2有效,但是,有更简洁的吗?)

Q3: How is the C Style cast doing for rValue? 问题3:C Style为rValue做了什么? (in other words, please explain why good case 1 works) (换句话说,请解释为什么好的案例1有效)

You can't static_cast between references (or pointers) to "unrelated types." 你不能在引用(或指针)之间static_cast到“不相关的类型”。 While you could static_cast from a CMyObject* to a CObject* , that isn't what you're doing here. 虽然你可以从CMyObject* static_castCObject* ,但这不是你在这里做的。 Here you're trying to cast a reference to a pointer into a reference to another pointer. 在这里,您尝试将指针的引用转换为对另一个指针的引用。 And the two pointer types do not have an inheritance relationship. 并且这两种指针类型没有继承关系。

I like your "good case 2" code--I'd run with that. 我喜欢你的“好案例2”代码 - 我会用它运行。

For more details on the non-relatedness of your pointer types, see here: static_cast and reference to pointers 有关指针类型的非相关性的更多详细信息,请参见此处: static_cast和对指针的引用

The proper way to write that code would be to use std::map<> . 编写该代码的正确方法是使用std::map<> Even if you insist on keeping the existing code mostly, consider fixing the interface of GetNextAssoc() to just return the pointer. 即使您坚持主要保留现有代码,也可以考虑修复GetNextAssoc()接口以返回指针。 In order to do that, you could simply add an overload of that function: 为此,您可以简单地添加该函数的重载:

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

Even more, you could template that function and do the conversion to the target type there. 更重要的是,您可以模拟该功能并在那里转换为目标类型。 Also, you could then use dynamic_cast , which should be used because formally, the container stores CObjects and they could have various, different types. 此外,您可以使用dynamic_cast ,这应该被使用,因为正式地,容器存储CObjects ,它们可以有各种不同的类型。

Now, why did I partially ignore your question? 现在,为什么我部分忽略了你的问题? The reason is that the MFC don't follow modern coding style and in some cases, they simply do things that are frowned on. 原因是MFC不遵循现代编码风格,在某些情况下,他们只是做一些不赞成的事情。 There are a bunch of justifications for that behaviour, but foremost it is age (didn't know better, didn't have proper template support) combined with compatibility concerns (can't change that now). 这种行为有很多理由,但最重要的是年龄(不知道更好,没有适当的模板支持)和兼容性问题(现在不能改变)。 That's not a reason to repeat these mistakes though. 这不是重复这些错误的理由。

Inspired by John Zwinck, I will look from a different angle: 受John Zwinck的启发,我将从不同的角度看待:

static_cast<CObject*>(pMine) 

will succeed because type "CMyObject" generalize from type "CObject"; 成功,因为类型“CMyObject”从类型“CObject”推广; actually, this is done implicitly; 实际上,这是隐含的;

static_cast<CMyObject*>(pObject) 

will succeed because type "CMyObject" generalize from type "CObject"; 成功,因为类型“CMyObject”从类型“CObject”推广;

static_cast<CObject**>(&pMine) 

will FAIL because type "CMyObject*" does NOT generalize from type "CObject*"; 因为类型“CMyObject *”没有从“CObject *”类型推广,所以会失败

reinterpret_cast<CObject**>(&pMine) 

will succeed at compile time because of "reinterpret_cast"; 因为“reinterpret_cast”而在编译时会成功 ; how about run time? 运行时间怎么样?

Let's make an assumption of the possible new implementation: 让我们假设可能的新实现:

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

So with calling this function by: 所以通过以下方式调用此函数:

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

the result is that "pMine" is pointing to an instance of "CMyObject"; 结果是“pMine”指向“CMyObject”的实例;

So runtime is SAFE . 所以运行时是安全的

However, if we insert the key-value by (Note: CYourObject has no generalize relationship to CMyObject) 但是,如果我们插入键值(注意:CYourObject与CMyObject没有通用关系)

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

and get it out by 并把它拿出来

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

Compile time will still succeed, however, pMine is now pointing to "CYourObject", which will be UNDEFINED BEHAVIOR at runtime . 编译时间仍然会成功,但是,pMine现在指向“CYourObject”,它将在运行时处于UNDEFINED BEHAVIOR状态 (static_cast has the same issue, though) (但static_cast有同样的问题)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM