What harsh examples are there showing C-style casts are bad?
Recently I found a great example of why C-style casts are bad. We start with a following class implementing multiple COM interfaces (I have two for brevity, but there can be ten in real life):
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;
}
The above implementation uses C-casts for adjusting pointers to account for multiple inheritance. They even work as static_cast
s - this
pointer value will be properly adjusted.
Now we copy-paste (or should I say reuse code of?) the same QueryInterface()
implementation to some other very similar class.
class CMyClassModified : public IInterface1 {
//declarations omitted
};
and leave the implementation the same. The new class doesn't inherit from IInterface2
anymore but
} else if( iid == __uuidof(IInterface2) ) {
*ppv = (IInterface2*)this;
}
will compile just fine and C-style cast will act as reinterpret_cast
- this
pointer value will be copied unchanged. The caller will obtain a pointer to an object that doesn't actually implement IInterface2
- straight way to undefined behavior. Such problems can be hard to spot in a huge database and when there're many (not two as in my example) interfaces.
If static_cast
was used that would not have happened - the compiler would emit an error trying to compile
*ppv = static_cast<IInterface2*>(this);
IMO that's a harsh enough example of how using C-style casts can cause serious problems. 开发者_JAVA技巧
What other examples are there?
This FAQ item sums up why C-casts are bad.
Any C-style cast is potentiality a bomb, since they are hiding conversion warnings and errors by silencing the compiler.
Since you wanted an example, here it is:
int main()
{
float a = 0.123;
double *b = ( double* ) &a;
*b = 0.123;
}
A very simple example:
class ClassB;//only forward declaration, no real declaration included
Class A * a;
Class B * b;
a = (ClassA *)b;
The cast will always be silently successful if there's only forward declaration of ClassB. It doesn't care if ClassB is derived from ClassA. And it will also be wrong when ClassB is not only derived from ClassA:
class ClassB:public SomeOtherClass, public ClassA {};
精彩评论