2010-01-28 14 views
6

He estado leyendo un artículo acerca de las interfaces de C++ (http://accu.org/index.php/journals/233) y estoy completamente perdido en la parte donde dice todas las funciones miembro virtuales deben ser privados artículo introduciendo C++ (la sección titulada "El fortalecimiento de la Separación "). Simplemente no tiene sentido para mí en absoluto.preguntas acerca de una interfaz

Según el autor, el código es así:

class shape { 
public: 
    virtual ~shape(); 
    virtual void move_x(distance x) = 0; 
    virtual void move_y(distance y) = 0; 
    virtual void rotate(angle rotation) = 0; 
    //... 
}; 

class line : public shape { 
public: 
    line(point end_point_1, point end_point_2); 
    //... 
private: 
    virtual ~line(); 
    virtual void move_x(distance x); 
    virtual void move_y(distance y); 
    virtual void rotate(angle rotation); 
    //... 
}; 

Así que tienen una función virtual pura que es pública, y su aplicación (en la clase de línea) que es privada.

¿Alguien podría explicar cómo se puede llamar a la función move_x? Su especificador de acceso es privado, que dará lugar a un error si trato de hacer esto:

line my_line(point(0,0), point(1,2)); 
my_line.move_x(-1); // does not compile 

Del mismo modo es correcto decir que la interfaz de dibujo (ver anteriormente en este artículo) no puede acceder a estas funciones, ya sea?

Gracias.

+1

Sólo traté de construir el código y que falla al compilar porque el destructor es privado ... – Patrick

Respuesta

6

La idea es que utilice esos métodos mediante una referencia o un puntero al shape.

shape &s = my_line; 
s.move_x(-1); 

Esto podría justificarse por motivos de "revelar sólo lo que necesita", o como una forma de auto-documentación. Demuestra que los métodos solo se llaman de la manera prevista.

+3

se considera mejor hábito de programación para forzar al programador (a sí mismo) para usar sólo la interfaz. – Ben

+0

No puedo decir que me gusta mucho la idea; si quiero una línea que es lo que quiero, no una forma que sea una línea. Si tengo una función que solo necesita los métodos proporcionados por la forma, entonces voy a pasar la línea en esa función como una forma, simplemente no puedo ver por qué lo harías, aunque +1 para la explicación. – Patrick

+0

Acepto que no es un consejo que cambia la vida. Como se muestra en las dos líneas de arriba, en realidad no restringe mucho las cosas, solo causa un pequeño inconveniente si el usuario parece tener que romper la regla. –

2

creo que el artículo pone de relieve la razón bien en esta cita:

Ahora, los únicos que pueden hacer los usuarios con línea es crear instancias de ella. Todo el uso de debe realizarse a través de su interfaz, es decir, la forma , imponiendo así una separación de interfaz/implementación más fuerte . Antes de dejar este tema, es importante para obtener algo correcto: el punto de imponer la separación interfaz/implementación es para no decirles a los usuarios qué hacer. Más bien, el objetivo es sustentar la separación lógica - el código ahora explica que la abstracción de la clave es la forma , y esa línea sirve para proporcionar una implementación de la forma.

Es decir, line no es en sí mismo interesante. Es solo una implementación de la interfaz shape, y puede haber otras implementaciones. Está especialmente interesado en la interfaz shape. Por lo tanto, solo debe acceder a la implementación a través de esta interfaz, y no como una clase independiente.

4

Si tiene un ejemplar del objeto line, puede tener la tentación de llamar a sus métodos. Pero si la única forma de obtenerlos es pidiendo su interfaz shape, entonces el objeto se parece menos a un objeto y más a una colección de interfaces.

Esto tiene más sentido si imagina que la línea implementa más de una interfaz.

3

Este consejo es aplicable solo a las jerarquías homogéneas, es decir, las jerarquías en las que las clases derivadas no introducen nuevas funciones (excepto los constructores) y simplemente anulan las funciones de la clase base. En este caso, obviamente no es necesario que trabaje directamente con la instancia line, solo mediante el puntero/referencia a shape.

Cuando tiene una jerarquía menos homogénea, este consejo no tiene mucho sentido: ¿cómo podría alguien aplicarlo a los casos cuando la clase derivada introduce nuevas funciones o las hereda de otra clase base? En este caso, a veces desea trabajar directamente con los objetos de la clase derivada directamente, y este consejo solo ocasionaría inconvenientes.

Desarrollo adicional de esta idea - menos radical y utilizable en más contextos - Non-Virtual Interface (NVI) por Herb Sutter.

+0

+1, también inhibe el uso de tipos de retorno covariantes –