2012-06-04 9 views
16

¿Hay alguna manera de evitar la repetición Graph:: en el archivo de implementación, y aun así dividir la clase en cabecera + implementación? Como por ejemplo en:¿Es posible evitar repetir el nombre de clase en el archivo de implementación?

del encabezado del archivo:

#ifndef Graph_H 
#define Graph_H 

class Graph { 
public: 
    Graph(int n); 
    void printGraph(); 
    void addEdge(); 
    void removeEdge(); 
}; 

#endif 

Implementación del archivo:

Graph::Graph(int n){} 
void Graph::printGraph(){} 
void Graph::addEdge(){} 
void Graph::removeEdge(){} 
+1

Esto se ve bien, suponiendo que no se olvide de '# include' el encabezado en la implementación. – dasblinkenlight

+3

¿Estás preguntando si puedes evitar escribir 'Graph ::' en la implementación? – GManNickG

+2

Sé que es correcto, pero estoy preguntando si hay otra manera sin tener que repetir Graph :: .. –

Respuesta

7

Supongo que esto es para evitar una gran cantidad de "tipeos innecesarios". Lamentablemente no hay forma de deshacerse del alcance (como muchas otras respuestas te han dicho) sin embargo, lo que hago personalmente es obtener la clase definida con todos mis prototipos de funciones en buenas filas, luego copiar/pegar en el archivo de implementación y luego ctrl-c su ClassName :: en el tablero de clip y ejecute la línea con ctrl-v. .

9

Si quiere evitar tener que escribir el "Gráfico ::" frente a la printGraph, addEdge etc., entonces la respuesta es "no", desafortunadamente. La característica de "clase parcial" similar a C# no es accesible en C++ y el nombre de cualquier clase (como "Gráfico") no es un espacio de nombres, es un ámbito.

+0

+1 para dos formas inspiradoras de ver la limitación. –

2

No, no hay forma de evitarlo. De lo contrario, ¿cómo sabría si una definición de función determinada es para una función de clase o para una función estática?

+0

Usted es, por supuesto, correcto para el estándar actual. Me gustaría pretender que estaba hablando hipotéticamente, aunque ;-) Así que según mis comentarios a OP: eliminaría la ambigüedad fácilmente utilizando la 'clase de espacio de nombres 'propuesta para definir los miembros: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html - y wow, espero que esto sea adorado ... y estoy muy triste, parece haber perdido C++ 17 :(Si alguien juzga esto trivial sobre una base SECA, solo piense en (A) los paralelos intuitivos al 'espacio de nombres 'normal y especialmente (B) implementando funciones de' plantilla 'fuera de línea, lo cual es insoportable. –

4

No, no hay. No directamente, al menos. Puede optar por trucos de preprocesador, pero no lo haga.

#define IMPL Graph:: 

IMPL Graph(int n){} 
void IMPL printGraph(){} 
void IMPL addEdge(){} 
void IMPL removeEdge(){} 

Además, no debería ni siquiera querer hacerlo. Cuál es el punto de. Además de ser una regla de C++, te permite saber que en realidad estás implementando una función de miembro.

+1

Eh, ¿es realmente inteligente decir "No hagas esto ... así es como"? – GManNickG

+2

@GManNickG Lo encuentro así, sí. Personalmente, me gusta saber esto ... –

+3

También podría definirlos en un archivo aparte y '#incluir' en el cuerpo de la clase. – Pubby

2

Si está preguntando si puede definir una función miembro como Graph::printGraph sin especificar la calificación del nombre de clase, entonces la respuesta es no, no de la manera que desea. Esto no es posible en C++:

archivo de implementación:

void printEdge(){}; 

Lo anterior compilará muy bien, pero no va a hacer lo que quiera. No definirá la función miembro con el mismo nombre dentro de la clase Graph. Más bien, declarará y definirá una nueva función gratuita llamada printEdge.

Esto es bueno y adecuado, si por su punto de vista es un poco molesto, porque es posible que desee dos funciones con el mismo nombre pero en diferentes ámbitos. Considere:

// Header File 
class A 
{ 
    void foo(); 
}; 

class B 
{ 
    void foo(); 
}; 

void foo(); 

// Implementation File 
void foo() 
{ 
} 

¿A qué alcance se aplica la definición? C++ no le impide tener diferentes funciones con los mismos nombres en diferentes ámbitos, por lo que debe decirle al compilador qué función está definiendo.

0

EDIT: He leído mal su pregunta :(esto sería una respuesta a la cuestión de si se puede dividir de encabezado y archivos siento

La respuesta simple: Se puede dividir C++ - archivo, pero no se puede dividir hasta encabezados-archivos.

La razón es bastante simple. Cada vez que su compilador necesita compilar un constructor, necesita saber exactamente cuánta memoria necesita asignar para dicho objeto.

por ejemplo:

class Foo { 
    double bar; //8 bytes 
    int goo; //4 bytes 
} 

'new Foo()' requeriría la asignación de memoria de 12 bytes. Pero si se le permitiera ampliar las definiciones de clase en varios archivos (es decir, dividir los archivos de encabezado), fácilmente haría un lío de esto. Su compilador nunca sabría si ya le contó todo sobre la clase, o si no lo hizo. Diferentes lugares en su código podrían tener diferentes definiciones de su clase, lo que llevaría a fallas de segmentación o errores extremadamente crípticos del compilador.

Por ejemplo:

h1.h:

class Foo { 
    double bar; //8 bytes 
    int goo; //4 bytes 
} 

h2.h: #include "h1.h"

class Foo { 
    double goo; //8 bytes 
}// we extend foo with a double. 

foo1.cpp:

#include "foo1.h" 

Foo *makeFoo() { 
    return new Foo(); 

} 

foo2.cpp:

#include "foo2.h" 

void cleanupFoo(Foo *foo) { 
    delete foo; 
} 

foo1.h:

#include "h1.h" 

Foo *makeFoo(); 

foo2.h:

#include "h1.h" 
#include "h2.h" 

void cleanupFoo(Foo *foo) 

main.cpp:

#include foo1.h 
#include foo2.h 

void main() { 
    Foo *foo = makeFoo(); 
    cleanupFoo(foo); 
} 

Ahora compruebe con mucho cuidado lo que sucede si primero se compila main.cpp a main.o, luego foo1.cpp a foo1.o y foo2.cpp a foo2.o, y fi finalmente, únelos a todos juntos. Esto debería compilarse, pero el makeFoo() asigna algo más que el cleanupFoo() desasignado.

Así que ahí lo tiene, puede dividir archivos .cpp, pero no divida clases sobre archivos de encabezado.

1
 //yes it is possible using preprocessor like this: 

     #define $ ClassName //in .cpp 

    void $::Method1() 
    { 
    } 

    //or like this: in the header .h: 

     #undef $ 
     #define $ ClassName' 

// but you have to include the class header in last #include in your .cpp: 

     #include "truc.h" 
     #include "bidule.h" ... 
     #include "classname.h" 

     void $::Method() { } 

     //i was using also 
     #define $$ BaseClass 
     //with single inheritance than i can do this: 

     void $::Method() 
     { 
     $$::Method(); //call base class method 
     } 

     //but with a typedef defined into class like this it's better to do this: 
     class Derived : Base 
     { 
     typedef Base $$; 

    } 
Cuestiones relacionadas