2010-02-01 15 views
5

¿Hay alguna razón para que la clase de implementación utilizada en el idioma pimpl tenga miembros privados? La única razón por la que realmente puedo pensar es para protegerse de usted mismo, es decir, los miembros privados sirven para imponer algún tipo de contrato entre la clase y el usuario, y en este caso la clase y el usuario están íntimamente relacionados, por lo que parece innecesario¿Miembros privados en la clase pimpl?

+2

Suponiendo una implementación agrupada para cadenas de sólo lectura, la clase de implementación puede tener un recuento de referencias para saber cuándo liberar la memoria, si es necesario. – dirkgently

+0

dirkgently: Me imagino que, para tener un conteo simple para todas las referencias a una cadena, ese conteo tendría que ser almacenado centralmente, dentro de la cadena y no en el contenedor. ¿Que me estoy perdiendo aqui? –

+0

@Steven Sudit: porque violaría el diseño; el recuento de referencias no es estrictamente parte de la estructura de datos necesaria para representar la cadena. – dirkgently

Respuesta

10

I Creo que la gente está confundiendo el idioma Pimpl con el Adaptador/Puente/Estrategia patrones. Los modismos son específicos de un idioma. Los patrones pueden aplicarse a muchos idiomas.

El modismo Pimpl se diseñó para abordar el siguiente problema en C++: Los miembros privados de una clase son visibles en la declaración de clase, lo que agrega innecesarias #include dependencias al usuario de la clase. Esta expresión también se conoce como compilador de firewall.

Si la implementación se escribe directamente en el archivo * .cpp correspondiente de la clase externa y no se puede acceder fuera del módulo, entonces Creo que está perfectamente bien simplemente usar una estructura para la clase Pimpl. Para más volver a reforzar la idea de que las implementaciones no están destinados a ser directamente reutilizado, yo los defino como una estructura interna privada:

// foo.h 
class Foo : boost::noncopyable 
{ 
public: 
    ... 

private: 
    struct Impl; 
    boost::scoped_ptr<Impl> impl_; 
}; 

// foo.cpp 
struct Foo::Impl 
{ 
    // Impl method and member definitions 
}; 

// Foo method definitions 

Tan pronto como hay un archivo de cabecera para la clase de implementación, creo que ya no están hablando del idioma Pimpl. Estamos hablando de Adaptador, Puente, Estrategia, clases de interfaz, etc. ...

Solo mis 2 centavos.

2

¿Por qué no debería tener miembros privados? El hecho de que esté definiendo una interfaz como PIMPL no significa que en ningún otro momento quiera usar la clase.

Todavía es una clase. Los datos probablemente deberían ser privados o estar protegidos. Operaciones sobre datos que nunca serán accesibles al público, privado o protegido. Operaciones que quizás desee exponer, proteger o publicitar.

+0

Mi razón principal para no querer miembros privados es pura pereza: no quiero ofrecer acceso. Me doy cuenta de que también puede haber miembros que deberían ser privados y que no requieren usuarios también. – Anne

+4

Es realmente una clase "privada", accesible solo dentro de un archivo cpp. Una estructura C-style está bien para el propósito en la mayoría de los casos. –

+0

Nemanja: Esto supone que el exterior y el interior se escriben al mismo tiempo. He agregado pimpl después del hecho a las implementaciones existentes. –

4

En teoría, una clase de pimpl es todavía una clase como cualquier otra. Que es una implementación concreta de una interfaz no significa que otro código no sea un cliente de la misma clase de pimpl.

Dicho esto, en la práctica he encontrado que las clases pimpl tienden a ser mucho más parecidas a las estructuras con algunas funciones miembro en lugar de objetos completos, y tienen menos necesidad de separar la interfaz de la implementación.

6

Depende de su implementación de pImpl, específicamente donde aplica la invariante de clase, pero en general no veo la necesidad de que la parte impl tenga miembros protegidos/privados. De hecho, generalmente lo declaro como una estructura.

0

(no he entendido bien la pregunta, así que voy a cambiar mi respuesta.)

La clase de aplicación, que está apuntado por la clase con el pimpl, debe haber una clase regular, con apenas tanto razón para ocultar detalles privados como cualquier otro. De hecho, a menudo es una clase preexistente, con la capa pimpl agregada más tarde para romper dependencias y quizás simplificar un poco la interfaz.

+0

La clase preexistente es la parte "externa", no la parte "impl". –

+0

Lo he visto en ambos sentidos. A veces pimpl es una forma de poner una interfaz consistente sobre las implementaciones que están sujetas a cambios. Otras veces, pimpl es una manera de ocultar completamente la implementación, rompiendo las dependencias en tiempo de compilación. De hecho, ambos pueden ser objetivos. –

1

La única razón por la que realmente ocurre es protegerse a sí mismo de

por lo que "privado" y "protegido" hay en el primer lugar. Por supuesto, debe usarlos en su implementación; el único momento en que no lo haría es si la implementación no tiene ningún comportamiento (en cuyo caso no es realmente una implementación).

0

Porque private significa una mejor encapsulación de datos.

Parece una tontería, lo sé, pero tenemos una manera de definir las interfaces en el trabajo que es muy simple:

class Interface; 

class Concrete { public: .... private: Interface* m_interface; } 

class ConcreteFoo: public Interface {}; 

La principal ventaja: se puede cambiar por otra ConcreteBar en cualquier momento. Es, de hecho, una combinación de Pimpl y Strategy patrón, y el constructor de Concrete llamará a Factory que será responsable de servir al objeto efectivo.

Si no puede pensar en una segunda forma de implementar el corazón, simplemente conéctelo en una clase.De esta forma, si luego tiene que refactorizar, solo tendrá que componer un resumen Interface con el mismo conjunto de métodos, cambiar algunos punteros (y el constructor) y estará bien;)

Cuestiones relacionadas