这不是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有效)
答案 0 :(得分:3)
在“无关类型”的引用(或指针)之间不能static_cast
。虽然您可以从static_cast
到CMyObject*
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有同样的问题)