2011-02-03 15 views
5

Recientemente encontré un gran ejemplo de por qué los moldes de estilo C son malos. Comenzamos con una clase siguiente implementar múltiples interfaces COM (tengo dos por razones de brevedad, pero no puede haber diez en la vida real):¿Qué duros ejemplos muestran que los moldes de estilo C son malos?

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; 
} 

La implementación anterior utiliza C-moldes para adjusting pointers to account for multiple inheritance. Incluso funcionan como static_cast s - this el valor del puntero se ajustará correctamente.

Ahora copiar y pegar (o debería decir la reutilización de código de?) El mismo QueryInterface() aplicación a alguna otra clase muy similar.

class CMyClassModified : public IInterface1 { 
    //declarations omitted 
}; 

y deje la implementación de la misma. La nueva clase no hereda de IInterface2 más, pero

} else if(iid == __uuidof(IInterface2)) { 
*ppv = (IInterface2*)this; 
} 

compilará bien y conversión de estilo C actuará como reinterpret_cast - this valor del puntero se copiará sin cambios. La persona que llama obtendrá un puntero a un objeto que en realidad no implementa IInterface2 - forma directa de comportamiento indefinido. Dichos problemas pueden ser difíciles de detectar en una gran base de datos y cuando hay muchas interfaces (no dos como en mi ejemplo).

Si se utilizó static_cast que no habría sucedido - el compilador emitiría un error al intentar compilar

*ppv = static_cast<IInterface2*>(this); 

OMI que es un ejemplo bastante duras de cómo el uso de moldes de tipo C pueden causar problemas graves.

¿Qué otros ejemplos hay?

+0

Una gran gotcha, pero no estoy del todo seguro de que esto es adecuado para SO. Parece muy discutidor. En el mejor de los casos es una wiki comunitaria. – tenpn

+0

@tenpn: No veo lo que se puede discutir aquí, solo un ejemplo de dispararse en la pierna en C++. – sharptooth

+1

@sharptooth pero eso no es una pregunta, ¿verdad? – tenpn

Respuesta

2

This FAQ item sumas todo sobre por qué los c-cast son malos.

Cualquier c-cast es potencialmente una bomba, ya que están ocultando advertencias de conversión y errores al silenciar el compilador.

Desde que quería un ejemplo, aquí está:

int main() 
{ 
    float a = 0.123; 
    double *b = (double*) &a; 
    *b = 0.123; 
} 
+0

Un buen artículo de preguntas frecuentes, pero se trata de moldes en general, no de cilindros en C específicamente. – sharptooth

+0

@sharptooth Supongo que tienes razón. Sin embargo, cada guía de estilo de codificación C++ decente le dirá que no use moldes de estilo c. –

1

Un ejemplo muy sencillo:

class ClassB;//only forward declaration, no real declaration included 

Class A * a; 
Class B * b; 
a = (ClassA *)b; 

El elenco siempre habrá silencio éxito si sólo hay declaración adelantada de ClassB. No importa si ClassB se deriva de ClassA. Y también será mal cuando ClassB no sólo se deriva de claseA:

class ClassB:public SomeOtherClass, public ClassA {}; 
Cuestiones relacionadas