2009-12-05 28 views
6

Si entiendo correctamente, tenemos al menos dos formas diferentes de implementar la composición. (El caso de aplicación con punteros inteligentes se excluye por razones de simplicidad casi no utilizar STL y no tienen ningún deseo de aprender..)¿Cómo implementar la composición de clase en C++?

Vamos a echar un vistazo a Wikipedia example:

class Car 
{ 
    private: 
    Carburetor* itsCarb; 
    public: 
    Car() {itsCarb=new Carburetor();} 
    virtual ~Car() {delete itsCarb;} 
}; 

Por lo tanto, es una forma: tenemos un puntero para objetar como miembro privado. Uno puede volver a escribir a tener este aspecto:

class Car 
{ 
    private: 
    Carburetor itsCarb; 
}; 

En ese caso tenemos un objeto como miembro privado. (Por cierto, ¿tengo razón al llamar a esta entidad un objeto desde el punto de vista de la terminología?)

En el segundo caso no es obligatorio llamar implícitamente al constructor predeterminado (si hay que llamar al constructor no predeterminado es es posible hacerlo en la lista de inicializadores) y destructor. Pero no es un gran problema ...

Y, por supuesto, en algunos aspectos estos dos casos difieren más apreciablemente. Por ejemplo, está prohibido llamar a métodos no const de la instancia Carburetor de métodos const de clase Car en el segundo caso ...

¿Hay alguna "regla" para decidir cuál usar? ¿Me estoy perdiendo de algo?

+1

Creo que quiere decir "está prohibido llamar a métodos no const de instancia de Carburador desde métodos const de clase de Auto". –

+0

@ Laurence Ooops. Por supuesto que sí ... – Wildcat

+8

"[No] tengo ganas de aprender [el STL]". ¿Qué? Te estás perdiendo una gran parte de C++ al ignorar el STL. – rlbond

Respuesta

7

En ese caso tenemos un objeto en sí mismo como miembro privado. (Por cierto, llamando a esta entidad como objeto ¿estoy escribiendo desde el punto de vista de la terminología?)

Sí, puede decir "un objeto" o "una instancia" de la clase.

También puede hablar sobre incluir el miembro de datos "por valor" en lugar de "por puntero" (porque "por puntero" y "por valor" es la forma normal de hablar sobre pasar parámetros, por lo tanto, espero que la gente lo entienda esos términos se aplican a los miembros de datos).

¿Hay alguna "regla" para decidir cuál usar? ¿Me perdí algo?

Si la instancia es compartida por más de un contenedor, entonces cada contenedor debe incluirla por puntero en lugar de valor; por ejemplo, si un Empleado tiene una instancia de Boss, incluya el Jefe por puntero si varias instancias de Empleados comparten el mismo Jefe.

Si la duración del miembro de datos no es la misma que la vida útil del contenedor, inclúyalo por puntero: por ejemplo, si el miembro de datos se crea una instancia después del contenedor o se destruye antes del contenedor o se destruye y recreado durante la vida útil del contenedor, o si alguna vez tiene sentido que el miembro de datos sea nulo.

En otro momento cuando debe incluir por puntero (o por referencia) en lugar de por valor es cuando el tipo del miembro de datos es una clase base abstracta.

Otra razón para incluir por puntero es que eso podría permitirle cambiar la implementación del miembro de datos sin volver a compilar el contenedor. Por ejemplo, si Car y Carburetor se definieron en dos archivos DLL diferentes, es posible que desee incluir Carburetor por puntero: porque entonces podría cambiar la implementación del Carburador instalando un Carburetor.dll diferente, sin reconstruir el Car.dll.

+0

+1 por mencionar referencias ya que parecen haberse pasado por alto hasta el momento – Glen

3

Composición: preferir miembro cuando sea posible. Use un puntero cuando se necesite polimorfismo o cuando se use una declaración directa. Por supuesto, sin puntero inteligente, la administración manual de la memoria es necesaria cuando se utilizan punteros.

1

Si Carb tiene la misma duración que Car, entonces la forma no puntero es mejor, en mi opinión. Si tiene que reemplazar el Carb in Car, entonces optaría por la versión del puntero.

8

Tiendo a preferir el primer caso porque el segundo requiere que # incluya Carburettor.h en Car.h. Dado que Carburettor es un miembro privado, no debería tener que incluir su definición en otro lugar que no sea el código de implementación real del automóvil. El uso de la clase Carburettor es claramente un detalle de implementación y los objetos externos que usan su objeto Car no deberían tener que preocuparse por incluir otras dependencias no obligatorias. Al usar un puntero, solo necesita usar una declaración de Carburador en Car.h.

+0

Esto es lo mismo en ambos casos, por lo que downvoted esto. –

+0

Puede ser más específico, estoy bastante seguro de que no entendió mi punto ... – nico

+2

No es lo mismo en ambos casos. Como señaló nicolascormier, puede usar una declaración directa para evitar incluir el archivo de encabezado. Tal vez deberías entender la respuesta antes de votar negativamente. –

0

Generalmente, la versión sin puntero es más fácil de usar y mantener.

Pero en algunos casos, no puede usarlo. Por ejemplo, si el automóvil tiene múltiples carburadores y desea colocarlos en una matriz, y el constructor del Carburador requiere un argumento: debe crearlos a través de nuevos y así almacenarlos como punteros.

Cuestiones relacionadas