2011-04-14 18 views
22

(En C++) Tengo una clase cuya estructura se declara en un archivo de encabezado. Ese archivo de encabezado está incluido en muchos archivos fuente, de modo que cuando lo edite necesito recompilar muchos archivos.Evitar declarar funciones privadas en archivos de encabezado de clase (C++)

La clase tiene un conjunto de funciones privadas que solo se llaman en un archivo fuente. Actualmente se declaran en la estructura de clases en el archivo de encabezado. Cuando agrego una nueva función de este tipo o edito los argumentos, por lo tanto, provoca la recompilación de muchos archivos. Me gustaría declarar las funciones en otro lugar, de modo que solo se recompile el archivo que las define y las llama (para ahorrar tiempo). Sin embargo, todavía necesitan poder acceder a las variables de clase internas.

¿Cómo puedo lograrlo?

+0

Existen enfoques que funcionan bien si escribo la clase desde cero. Sin embargo, no estoy empezando desde cero; esta clase ya está escrita. – user664303

Respuesta

4

No hay forma de declarar las funciones de miembro de una clase fuera de la declaración de clase principal. Entonces, si desea declarar, fuera de la clase en cuestión, las funciones que pueden acceder a las variables miembro de una instancia particular de la clase, entonces no veo otra alternativa que pasar esa instancia a la función. Además, si desea que las funciones puedan acceder a las variables privadas y protegidas, tendrá que ponerlas en una nueva clase y hacer que la clase original sea amiga de eso. P.ej.

header.h:

class FooImpl; 

class Foo { 
public: 
    int bar(); 
    friend class FooImpl; 
private: 
    int var; 
} 

impl.cpp:

#include "header.h" 

class FooImpl { 
public: 
    int bar(Foo &); 
} 

int FooImpl::bar(Foo &foo) { 
return foo.var; 
} 

int Foo::bar() { 
return FooImpl::bar(*this); 
} 
+0

Este es mi entendimiento hasta ahora, pero no estoy 100% seguro. Comentarios recibidos con gratitud. – user664303

+0

Aún tiene 'int var' en la' clase Foo'. ¿No es el objetivo de la pregunta moverlo a 'clase FooImpl'? – balki

+1

@balki: No, el objetivo de esta pregunta era cómo agregar o editar _funciones privadas_ en una clase, sin cambiar el encabezado. Si muevo las variables privadas a FooImpl, también tengo que reenviar todas las funciones públicas existentes a esa clase. Vea mi primer comentario a la respuesta de Erik sobre eso. – user664303

14

Use la pImpl idiom - Su clase visible mantiene un puntero a la clase real y reenvía las llamadas a las funciones miembro públicas.

EDIT: En respuesta a los comentarios

// Foo.h: 

class FooImpl; // Do *not* include FooImpl.h 
class Foo { 
public: 
    Foo(); 
    ~Foo(); 
    //.. also need copy ctor and op= 
    int bar(); 
private: 
    FooImpl * Impl; 
}; 

// FooImpl.h: 

class FooImpl { 
public: 
    int bar() { return Bar; } 
private: 
    int Bar; 
}; 

// Foo.cpp: 

#include "FooImpl.h" 

Foo::Foo() { Impl = new FooImpl(); } 
Foo::~Foo() { delete Impl; } 
int Foo::bar() { return Impl->bar(); } 

Mantener la implementación real de su clase en FooImpl - Foo debe tener copias de los miembros públicos de FooImpl y pide simplemente adelante a estos. Todos los usuarios incluirán solo "Foo.h". Puede cambiar todos los detalles privados de FooImpl sin que los usuarios de Foo vean los cambios.

+0

Gracias. Es una buena idea en general. Sin embargo, en este caso no comencé a utilizar este marco, por lo que necesitaría una reescritura extensa de mi clase, incluida la escritura de envoltorios para todas sus funciones públicas. Me gustaría simplemente poder enviar un subconjunto de funciones privadas fuera del encabezado, sin demasiada molestia. – user664303

+0

@ user664303: La herencia * puede * ser una solución - este problema en particular es una de las falacias molestas de C++ imo. – Erik

+0

¿Estoy en lo cierto al pensar que necesariamente requerirá un molde del puntero de instancia de clase, por ejemplo .: ((priv_class *) this) -> priv_func() ;. ¿O hay una forma de evitar esto? – user664303

1

crear una clase base abstracta que contiene sólo las funciones públicas y la referencia de esto en sus cabeceras. Crea tu clase real como una implementación en otro lugar. Solo los archivos fuente que necesitan crear su clase necesitan ver el encabezado de la clase de implementación.

Cuestiones relacionadas