2012-02-29 12 views
8

EDITAR: Esta es una discusión sobre las mejores prácticas en el caso (simplificado) presentado a continuación. Cualquier herramienta, estilo de codificación u otra cosa que quieras sugerir, publícala. Gracias.¿Hay alguna manera especial de declarar/definir constructores C++ (y destructores)

¿Por qué no hay formas especiales de declarar o definir ctors/dtors sin duplicar el nombre de la clase? Es molesto, especialmente cuando se crean prototipos y terminan cambiando mucho el nombre de la clase.

Lo que quiero decir es algo con typedef así:

struct SomeClassThatDoesSomething { 
    typedef SomeClassThatDoesSomething ThisClass; 
    ThisClass() { PrepareToDie(); } 
    ThisClass(int a) : _a(a) { PrepareToDie(); } 
    ThisClass(float a, int b) : _b(a), _a(b) { PrepareToDie(); } 
    ThisClass(float a, char * b) : _b(a), _c(b) { PrepareToDie(); } 
    ThisClass(char * a, int b) : _c(a), _a(b) { PrepareToDie(); } 
    ThisClass(ThisClass &rhs) { } 
    ~ThisClass() {} 
    void Burn() {} 
    void PrepareToDie() {} 
    int _a; 
    float _b; 
    char *_c; 
}; 

struct SomeDerivedClassThatDoesSomething : public SomeClassThatDoesSomething { 
    typedef ThisClass BaseClass; 
    typedef SomeDerivedClassThatDoesSomething ThisClass; 
    ThisClass(BaseClass &is_not_amused) : BaseClass(is_not_amused) { BaseClass::_a = 1; PrepareToDie(); } 
    ThisClass(float a, char * b) : BaseClass(b, a) {} 
    ~ThisClass() { BaseClass::Burn(); } 
    unsigned int _a; // Different semantics up the tree. 
}; 

//EDIT: Consider this: Enforce export name decoration policy. 
#define DLL_API __declspec(dllexport) 
// ... or dllimport - not the point here 
#define def_export_struct(name) struct C##name; typedef C##name *P##name; struct DLL_API C##name 

def_export_struct(SomeOtherClassThatDoesSomething) : public SomeDerivedClassThatDoesSomething 
{ 
//... 
}; 
namespace mass_destruction { 
    def_export_struct(Int) 
    { 
    //... (The point is that search and replace gets very unreliable in big projects) 
    } 
}; 

Sólo funciona para ctors y sólo en MSVC; Lo he estado usando y, aunque no es una gran característica, hace la vida más fácil. Este es un ejemplo trivial, pero imagine una estructura bastante complicada. (Un efecto secundario útil también es que tienes un alias en clase sin tener que rastrear su nombre.) ¿Me falta algo? ¿De verdad soy el único que necesita esto? El punto no es si se compila, el punto es que lo tengo trabajando en parte para mí y hace maravillas. Hasta que llegue al estándar ... (Esta no es una discusión de cumplimiento)

+4

IDEs modernos tienen capacidades de refactorización decentes (o hay complementos que los proporcionan), por lo que renombrar una clase es muy simple. Por lo tanto, no veo la necesidad de tal característica. –

+1

No está muy claro lo que estás preguntando. Si existe tal característica, o * por qué * no existe, ¿algo más? Y al decir que ya conoce una de estas funciones y que no le interesa el cumplimiento, es difícil saber qué más quiere. – jalf

+4

@ BjörnPollex: las capacidades de refactorización para C++ generalmente van muy por detrás de sus contrapartes Java/C#. Y aparte de eso, no todos usan IDE en absoluto, y no es el propósito de un IDE hacer que las mejoras de lenguaje * sean innecesarias * – jalf

Respuesta

6

¿Has oído hablar alguna vez de buscar y reemplazar?

Supongo que la mayoría de la gente usa ex, vim, sed. etc .: s/search/replace/g o equivalente para cambiar el nombre de sus clases, o no las cambien para no molestarlas por la falta de esta característica.

Se puede usar un #define hacer esto dócilmente:

#define THIS_CLASS MyLongClassNameThatIChangeLotsAndLots 
class THIS_CLASS{ 
    THIS_CLASS() { PrepareToDie(); } 
    THIS_CLASS(int a) : _a(a) { PrepareToDie(); } 
    THIS_CLASS(float a, int b) : _b(a), _a(b) { PrepareToDie(); } 
    THIS_CLASS(float a, char * b) : _b(a), _c(b) { PrepareToDie(); } 
    THIS_CLASS(char * a, int b) : _c(a), _a(b) { PrepareToDie(); } 
    THIS_CLASS(THIS_CLASS &rhs) { } 
    ~THIS_CLASS() {} 
}; 
#undef THIS_CLASS 

Lo que es molesto, estoy de acuerdo, es la falta de una forma estándar para referirse a la clase base (s) de un tipo - - normalmente privada typedef ... base_t en las clases, a continuación, el uso que de las listas initialiser, etc.

+1

preparetoDie() ... +1 – UmNyobe

+0

También uso sed, pero no está disponible en algunos sistemas. Su macro no ayuda mucho porque las clases pueden tener constructores distintos. No puede suponer siquiera un conjunto mínimo de ctors comunes. Personalmente creo que no vale la pena el tiempo. – jweyrich

+0

Otro problema es que la redefinición de macro se pone fea con #pragma push_macro ("THIS_CLASS") y #pragma pop_macro ("THIS_CLASS"). Doable, pero más difícil de rastrear. Guardaría tal cosa por menos de definiciones comunes. – ActiveTrayPrntrTagDataStrDrvr

3

Si sus nombres de clase son cada vez más frustrante largo aliento, considere hacer un mayor uso de namespace.

namespace, combinado con using es ideal para que sus nombres de tipos sean tan detallados como lo requiera cada contexto.

namespace Something 
{ 
    struct Derived : public SomeClass 
    { 
    Derived() {...etc.} 

    } 
} 
+0

Los nombres largos son exagerados a propósito. Pero volvamos a su respuesta: ¿esto no hace que la búsqueda y el reemplazo sean más difíciles? Introducirá muchos nombres duplicados. – ActiveTrayPrntrTagDataStrDrvr

+0

@ user1240436: Hace que s/r sea más difícil, sí. Mi respuesta no se aplica realmente después de su edición. –

+0

Todavía es útil como una forma de planificar un proyecto más pequeño. – ActiveTrayPrntrTagDataStrDrvr

Cuestiones relacionadas