最近我发现了一个很好的例子,说明为什么C风格的演员阵容很糟糕.我们从下面的类开始实现多个COM接口(为了简洁我有两个,但在现实生活中可能有十个):
class CMyClassInitial : public IInterface1, public IInterface2 {
//declarations omitted
};
HRESULT CMyClassInitial::QueryInterface(REFIID iid, void** ppv)
{
if( ppv == 0 ) {
return E_POINTER;
}
*ppv = 0;
if( iid == __uuidof(IUnknown) || iid == __uuidof(IInterface1) ) {
*ppv = (IInterface1*)this;
} else if( iid == __uuidof(IInterface2) ) {
*ppv = (IInterface2*)this;
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
Run Code Online (Sandbox Code Playgroud)
上面的实现使用C-casts来调整指针以考虑多重继承.它们甚至可以作为static_casts - this指针值进行适当调整.
现在我们复制粘贴(或者我应该说重用代码?)相同的QueryInterface()实现到其他一些非常相似的类.
class CMyClassModified : public IInterface1 {
//declarations omitted
};
Run Code Online (Sandbox Code Playgroud)
并使实现保持不变.新类不再继承IInterface2了
} else if( iid == __uuidof(IInterface2) ) {
*ppv = (IInterface2*)this;
}
Run Code Online (Sandbox Code Playgroud)
将编译得很好并且C风格的强制转换将充当reinterpret_cast- this指针值将被复制不变.调用者将获得指向实际上未实现的对象的指针IInterface2 - 直接指向未定义的行为.这样的问题很难在庞大的数据库中找到,并且当有很多(在我的例子中不是两个)接口时.
如果static_cast使用了不会发生的事情 - 编译器会在尝试编译时发出错误
*ppv = static_cast<IInterface2*>(this);
Run Code Online (Sandbox Code Playgroud)
对于如何使用C风格的演员表而言,IMO是一个非常严厉的例子,可能会导致严重的问题.
还有哪些其他例子?
此常见问题解答项目总结了 C 型铸造不好的原因。
任何 C 风格的强制转换都可能是炸弹,因为它们通过使编译器静音来隐藏转换警告和错误。
既然你想要一个例子,那就是:
int main()
{
float a = 0.123;
double *b = ( double* ) &a;
*b = 0.123;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1791 次 |
| 最近记录: |