简体   繁体   中英

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.

What other examples are there?

This FAQ item sums everything about why c-casts are bad.

Any c-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 {};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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