2010-01-28 8 views
6

Ho letto un articolo sulle interfacce C++ (http://accu.org/index.php/journals/233) e sono completamente perso nella parte in cui si dice che tutte le funzioni dei membri virtuali dovrebbero essere rese private (la sezione intitolata "Rafforzare la separazione "). Non ha proprio senso per me.domande su un articolo che introduce l'interfaccia C++

Secondo l'autore, il codice è come questo:

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); 
    //... 
}; 

Così abbiamo una funzione di pura virtuale che è pubblico, e la sua attuazione (nella classe di linea) che è privato.

Qualcuno potrebbe spiegare come si può chiamare la funzione move_x? Il suo specificatore di accesso è privata, che porterà a un errore se provo a fare questo:

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

Allo stesso modo è corretto dire che l'interfaccia di disegno (vedi in precedenza in questo articolo) non può accedere a queste funzioni sia?

Grazie.

+1

Ho appena provato a compilare il codice e non riesce a compilare perché il distruttore è privato ... – Patrick

risposta

6

L'idea è che usereste questi metodi tramite un riferimento o un puntatore a shape.

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

Questo potrebbe essere giustificata per motivi di "rivelare solo ciò che è necessario", o come una forma di auto-documentazione. Dimostra che i metodi sono solo chiamati nel modo previsto.

+3

Si considera migliore abitudine di programmazione forzare il programmatore (te stesso) a utilizzare solo l'interfaccia. – Ben

+0

Non posso dire che mi piaccia molto l'idea; se voglio una linea questo è ciò che voglio, non una forma che sembra essere una linea. Se ho una funzione che richiede solo i metodi forniti dalla forma, passerò la linea in quella funzione come forma, ma non riesco a capire perché faresti questo, +1 per la spiegazione però. – Patrick

+0

Sono d'accordo che non è un consiglio che cambia la vita. Come mostrato dalle due righe sopra, in realtà non limita molto le cose - causa solo un piccolo inconveniente se l'utente sembra aver bisogno di infrangere la regola. –

2

Penso che l'articolo mette in evidenza la ratio bene in questa citazione:

Ora, l'unica cosa che gli utenti possono fare con linea è creare istanze di esso. Tutto l'utilizzo di deve avvenire tramite la sua interfaccia, ad esempio la forma , rafforzando così l'interfaccia/separazione dell'implementazione . Prima di lasciare questo argomento, è importante che sia corretto: il punto di applicazione della separazione dell'interfaccia/implementazione è per non dire agli utenti cosa fare. Piuttosto, l'obiettivo è sostenere la separazione logica - il codice ora spiega che l'astrazione chiave è la forma , e quella linea serve a fornire un'implementazione della forma a .

Cioè, line non è di per sé interessante. È solo un'implementazione dell'interfaccia shape e potrebbero esserci altre implementazioni. Sei particolarmente interessato all'interfaccia shape. Quindi, è necessario accedere all'implementazione solo tramite questa interfaccia e non come una classe autonoma.

4

Se si dispone nell'oggetto line, si potrebbe essere tentati di chiamare i suoi metodi. Ma se l'unico modo per ottenerli è chiedere l'interfaccia shape, l'oggetto sembra meno simile a un oggetto e più simile a una collezione di interfacce.

Questo ha più senso se si immagina la linea che implementa più di un'interfaccia.

3

Questo consiglio è valido solo per le gerarchie omogenee, ovvero per le gerarchie in cui le classi derivate non introducono nuove funzioni (eccetto i costruttori) e sostituiscono semplicemente le funzioni della classe base. In questo caso ovviamente non è necessario lavorare direttamente con l'istanza line - solo tramite puntatore/riferimento a shape.

Quando si ha una gerarchia meno omogenea, questo consiglio non ha molto senso: come si applicherebbe qualcuno ai casi in cui la classe derivata introduce nuove funzioni o le eredita da un'altra classe base? In questo caso a volte vuoi lavorare direttamente con oggetti di classe derivata direttamente, e questo consiglio potrebbe portare solo a degli inconvenienti.

Ulteriore sviluppo di questa idea - meno radicale e utilizzabile in più contesti - Non-Virtual Interface (NVI) di Herb Sutter.

+0

+1, inibisce anche l'uso dei tipi di ritorno covarianti –