2010-09-01 17 views
12

Ojalá pudiera devolver un objeto de clase base virtual para que no tenga que ocuparme de la gestión de memoria (la idea de programación de funciones también estimula esta búsqueda). Eso significa que estoy buscando algunas cosas como a continuación:siempre debe devolver un puntero a la clase en el diseño de la interfaz?

class Car 
{ 
    public: 
    virtual int price() = 0 ; 
    virtual string brand() = 0 ; 
} 

class Interface 
{ 
    public: 
    virtual Car giveMeACar() = 0 ; 
    virtual vector<Car> listMeAllTheCars() = 0 ; 
} 

Sin embargo, esto ni siquiera compilará debido a que el coche es una interfaz abstracta, con un mensaje de error:

inválida tipo abstracto de devolución para función de miembro 'virtual Car giveMeACar() = 0; porque las siguientes funciones virtuales son puras dentro de 'Car': int price()
string brand();

es así, ¿eso significa que tengo que revisar la interfaz a algo así como a continuación y gestor de la memoria a mí mismo (eliminar la instancia después de usarlo) - descartando la opción de utilizar el puntero inteligente.

class Interface 
{ 
    public: 
    virtual Car* giveMeACar() = 0 ; 
    virtual vector<Car*> listMeAllTheCars() = 0 ; 
} 

Mi pregunta es: ¿es esta la única opción que tengo cuando diseño de una interfaz donde cada cosas (clase) es abstracto?

Devolver un objeto de clase de interfaz es perfecto válido en Java. C++ parece ser litera poco detallado y contra intuitivo en esta faceta. Más que a menudo, creo que C++ es un "puntero al lenguaje de programación de objetos" en lugar de un "lenguaje de programación de objetos" porque sin un puntero no se obtienen demasiados beneficios de la programación de objetos.

+0

+1 para realizar funciones virtuales privadas: – Chubsdad

+1

@chubsdad: Why? Esa no es mi intención ... Debería haber usado public – pierrotlefou

+1

-1 entonces, ver el modismo Non Virtual Interface. Por ejemplo, no puede aplicar invariantes en los límites de su interfaz si los métodos públicos son virtuales. –

Respuesta

7

En Java, "regresar y objeto" es en realidad semánticamente equivalente a devolver un puntero al objeto en C++, está tratando de devolver un objeto por valor, lo que hace una copia de él. No puedes hacer una copia de un objeto abstracto.

Por lo tanto, aunque C++ puede ser más detallado, admite semántica diferente para pasar parámetros y devolver valores, lo que Java no admite (retorno por valor, pase por referencia).

Dicho esto, debe regresar con el puntero inteligente, que hace la gestión de la memoria por usted. Otros han señalado auto_ptr con semántica de transferencia de propiedad, pero también puede usar boost::shared_ptr; en caso de que utilice una asignación de memoria personalizada internamente (por ejemplo, un grupo), la función de eliminación personalizada de shared_ptr le ayudará a ocultar detalles de desasignación del usuario de la interfaz. También se puede usar en contenedores STL (a diferencia de auto_ptr).

class Car 
{ 
public: 
    typedef boost::shared_ptr<Car> Ptr; 
    virtual int price() = 0 ; 
    virtual string brand() = 0 ; 
}; 

class Interface 
{ 
public: 
    virtual Car::Ptr giveMeACar() = 0 ; 
    virtual vector<Car::Ptr> listMeAllTheCars() = 0 ; 
} 
+0

Me encanta la sintaxis después de introducir el impulso. Sin embargo, para un proyecto integrado, la tarea de compilar de forma cruzada el impulso y el problema inesperado que siempre me impide usarlo ... – pierrotlefou

+0

@pierr, sí, el impulso es un poco de cerdo, pero 'shared_ptr' tiene una implementación de solo encabezado , no necesita vincular a ninguna biblioteca de impulso. También puede verificar si su compilador admite 'std :: tr1 :: shared_ptr' (GCC 4+, MSVC 2008 con paquete de características), entonces no necesita impulso en absoluto. –

+0

Afortunadamente, mi compilador cruzado admite std :: tr1 :: shared_ptr – pierrotlefou

1

Creo que this puede ser de utilidad.

+2

Para las personas que leen la página, es bueno si hay alguna pista hacia dónde conduce el enlace ... –

4

Sus observaciones son correctas, no hay una manera fácil de hacer lo que quiere hacer. En C++ no puede devolver un automóvil por valor porque (entre otras cosas) la persona que llama necesita asignarle espacio.

Java no es fundamentalmente diferente, es solo que su sintaxis no puede expresar lo que desea expresar; todos los tipos (excepto los tipos primitivos) tienen un '*' implícito adjunto. Y tiene recolección de basura, por lo que no necesita preocuparse por la administración de la memoria.

+0

¿Quisiste decir "su sintaxis PUEDE expresar lo que quieres expresar"? – pierrotlefou

+2

No, quise decir "no puedo". Java no puede expresar el acto de devolver una clase por valor. Todas las clases se pasan implícitamente por referencia. Probablemente el Java más cercano a "Car x = giveMeACar();" en C++ es "Car x = (Car) giveMeACar(). clone();" (si el coche implementa el método de clonación correctamente). –

+0

Estoy confundido. Java siempre debe pasar por valor. http://stackoverflow.com/questions/40480/is-java-pass-by-reference – pierrotlefou

2

La otra opción es utilizar una plantilla:

template<class CarClass> 
class Interface { 
    virtual CarClass giveMeACar() = 0; 
    virtual vector<CarClass> listMeAllTheCars() = 0; 
} 
3

devolver un std::auto_ptr<Car>. Pone el objeto en el montón como un puntero, pero lo elimina cuando sale del ámbito como una variable de pila.

Las variaciones incluyen boost::unique_ptr y C++ 0x std::unique_ptr, que reemplaza auto_ptr.

vector<Car> no puede reemplazarse por vector< auto_ptr<Car> > porque auto_ptr es incompatible con los contenedores. Necesitas usar unique_ptr para eso.

+0

Y para la concisión, la capacidad de escritura y un único punto de mantenimiento para alternar entre estos tipos de punteros (si más tarde es necesario para el rendimiento, etc.), es posible que desee crear un typedef. Este es un enfoque bastante común. –

+1

[¡Enhorabuena!] (Http://stackoverflow.com/badges/49/c?userid=153285) –

0

Otras publicaciones en respuesta a su consulta responden perfectamente a su consulta.Sin embargo, sólo tenía unas pocas observaciones que usted puede considerar

Primera observación:

Evite exponer los detalles acerca de la aplicación con el mundo exterior.

esto es con respecto al tipo de retorno de

virtual vector<Car> listMeAllTheCars() = 0 ;.

¿Por qué deberían los usuarios de la clase saber si está usando vector o list o algo más? Consulte el patrón de diseño del iterador de GOF. C++ tiene un buen soporte para iteradores.

Segunda observación:

Su requisito parece imitar la necesidad de patrón de diseño Factory Method especialmente cuando miro

virtual Car giveMeACar() = 0 ;

Es posible que desee ver en el método de fábrica del diseño del modelo

Tercera observación:

Sin embargo, la presencia de estos dos tipos de diversión en una sola interfaz, me parece un poco fuera de lugar. Es posible que desee considerar el diseño de nuevo. Se adhieren a Single Responsibility Principle.

Cuestiones relacionadas