最近我发现了一个很好的例子,说明为什么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;
}
上述实现使用adjusting pointers to account for multiple inheritance的C-cast。它们甚至可以在static_cast
s - this
指针值正确调整后工作。
现在我们将相同的QueryInterface()
实现复制粘贴(或者我应该说重用代码)到其他一些非常相似的类。
class CMyClassModified : public IInterface1 {
//declarations omitted
};
并使实现保持不变。新课程不再继承IInterface2
,而是
} else if( iid == __uuidof(IInterface2) ) {
*ppv = (IInterface2*)this;
}
将编译得很好,C风格的强制转换将充当reinterpret_cast
- this
指针值将被复制不变。 调用者将获得指向实际上未实现IInterface2
的对象的指针 - 直接指向未定义的行为。这样的问题很难在庞大的数据库中发现,并且当有很多(在我的例子中不是两个)接口时。
如果使用的static_cast
不会发生 - 编译器会在尝试编译时发出错误
*ppv = static_cast<IInterface2*>(this);
IMO是一个非常严厉的例子,说明如何使用C风格的演员阵容会导致严重的问题。
还有哪些其他例子?
答案 0 :(得分:2)
This FAQ item总结了为什么c-casts不好的一切。
任何c-cast都是潜在的炸弹,因为它们通过使编译器静音来隐藏转换警告和错误。
既然你想要一个例子,那就是:
int main()
{
float a = 0.123;
double *b = ( double* ) &a;
*b = 0.123;
}
答案 1 :(得分:1)
一个非常简单的例子:
class ClassB;//only forward declaration, no real declaration included
Class A * a;
Class B * b;
a = (ClassA *)b;
如果只有ClassB的前向声明,演员阵容将永远成功。它不关心ClassB是否来自ClassA。 当ClassB不仅来自ClassA时也是错误的:
class ClassB:public SomeOtherClass, public ClassA {};