25

Ho appena notato questo in un certo codice:Perché una funzione virtuale dovrebbe essere privata?

class Foo { 
[...] 
private: 
    virtual void Bar() = 0; 
[...] 
} 

Questo ha uno scopo?

(sto cercando di porto qualche codice da VS a G ++, e questo ha attirato la mia attenzione)

+1

Mi dispiace, quale parte ti confonde esattamente? – drxzcl

+20

La parte "privata". – liori

+8

Non so se la gente sta inviando il commento precedente perché suona comico o perché sono anche confusi ... –

risposta

23

Vedere this Herb Sutter article sul motivo per cui ci si vuole fare una cosa simile

+8

parafrasi migliore o riassumi la risposta con parole tue. natura distribuita ftw. ;) – wilhelmtell

+8

No, meglio di no. Non so quali siano le abilità pedagogiche di Greg, ma dubito che siano migliori di Sutters. –

+2

Quindi, in sostanza, il punto qui è quello di applicare il modello di metodo del modello? In modo che la classe derivata possa sovrascrivere il metodo, ma solo la classe base può mai chiamarla? Immagino sia utile, ma dal momento che la classe derivata può semplicemente creare il proprio metodo interno e chiamarla da Bar(), non sono sicuro che si qualifichi come qualcosa di più di un suggerimento. – jprete

2

Si tratta di una funzione virtuale pura. Qualsiasi implementazione finale che sia dervitata da "Foo" DEVE implementare la funzione "Bar".

+0

tranne che è contrassegnato come "privato". Il PO non chiarì la sua domanda, e dovetti guardarlo per un secondo o due prima che mi rendessi conto che era contrassegnato come privato, quindi +1 per annullare il -1. –

1

Rende la funzione virtuale pura anziché virtuale.

Nessuna implementazione viene fornita per impostazione predefinita e l'intento è che l'implementazione della funzione deve essere specificata da una classe ereditaria. Questo può essere annullato comunque.

A volte si vedono classi complete in cui tutte le funzioni membro vengono specificate come virtuali allo stato puro in questo modo.

Queste sono classi base astratte, a volte denominate classi di interfaccia e il progettista dell'ABC sta dicendo a te: "Ora ho idea di come questa funzionalità possa essere implementata per tutte le specializzazioni di questa classe base. deve avere tutti questi elementi definiti affinché la tua specializzazione funzioni e tu sai come dovrebbe comportarsi il tuo oggetto ".

Modifica: Oops, abbiamo appena notato che la funzione virtuale pura del membro è privata. (Grazie Michael) Cambia leggermente le cose.

Quando questa classe base viene ereditata utilizzando l'ereditarietà privata, le cose cambiano. Fondamentalmente ciò che sta facendo il progettista della classe base è che, quando la classe derivata chiama una funzione non privata nella classe base. parte del comportamento è stata delegata alla specializzazione della funzione nella classe derivata. Il membro non privato sta facendo "qualcosa" e parte di quel "qualcosa" è una chiamata, tramite la pura funzione della classe base virtuale, alla tua implementazione.

Quindi alcune funzioni pubbliche in Foo chiamano la funzione Barra all'interno di Foo, e si basa sul fatto che fornirai un'implementazione specializzata della funzione Bar per il tuo caso particolare.

Scott Meyers definisce "implementato in termini di".

BTW Solo ridacchiando sul numero di risposte che sono state rapidamente eliminate da persone che non hanno visto la "stampa fine" nella domanda! (-:.

HTH

applausi,

0

L'unico scopo sembra servire è quello di fornire un'interfaccia comune .

BTW, anche se una funzione è dichiarata come privata virtuale, può ancora essere implementato e chiamato con l'istanza di classe o da amici.

Ciononostante, questo genere di cose solitamente serviva da interfaccia, ma non lo faccio in questo modo.

5

ho intenzione di citare una breve spiegazione dal grande C++ FAQ Lite che riassume bene:

[23.4] Quando qualcuno dovrebbe usare privati ​​ virtuali?

Quasi mai.

I virtual protetti sono ok, ma i virtual virtuali di tipo sono in genere una perdita netta . Motivo: i virtual private confondono i programmatori C++ e la confusione aumenta i costi, la pianificazione dei ritardi e riduce il rischio.

I nuovi programmatori C++ vengono confusi dai virtual virtuali perché pensano che un virtual privato non possa essere sovrascritto. Una classe derivata non può accedere a membri di base privati ​​nella sua classe base , quindi come potrebbe chiedere a di sovrascrivere un virtual privato dalla sua classe base ? Ci sono spiegazioni per sopra, ma questo è accademico. Il vero problema di è che quasi tutti gli vengono confusi la prima volta che eseguono in virtual private e la confusione non è buona.

A meno che non vi sia un motivo valido per al contrario, evitare i virtual privati.


Il C++ FAQ Lite è stato aggiornato nel frattempo:

Tra l'altro, confonde maggior parte dei programmatori alle prime armi C++ che virtuali private possono essere sovrascritte, e tanto meno sono validi a tutti. Ci è stato insegnato a tutti che i membri privati ​​in una classe base non sono accessibili nelle classi derivate da essa, il che è corretto. Tuttavia questa inaccessibilità della classe derivata non ha nulla a che fare con il meccanismo di chiamata virtuale, che è alla classe derivata. Dal momento che ciò potrebbe confondere i novizi, , le domande frequenti su C++ precedentemente raccomandavano l'utilizzo di virtual protetti anziché di virtual private. Tuttavia, l'approccio virtuale privato è ormai abbastanza comune che la confusione dei novizi è meno preoccupante.

+2

Penso che Cline e Sutter non siano d'accordo. Vedi il link nella risposta di Greg Rogers. –

+5

Questo è il motivo per cui non mi piacciono le FAQ C++, il suo pieno di opinioni che sono a volte semplicemente stupide, e va contro le migliori pratiche definite da alcuni dei principali pensatori nel campo. Vedi Herb Sutters rispondere per una spiegazione molto migliore che ha un'opinione aperta. –

+0

La libreria standard di streaming è anche un ottimo posto per vedere esempi di funzioni virtuali private con pubblico non virutale che li utilizzano. –

5

La solita risposta "accademica" è: gli specificatori di accesso e la virtualità sono ortogonali - uno non influenza l'altro.

Una risposta un po 'più pratica: le funzioni virtuali private vengono spesso utilizzate per implementare il modello di progettazione Template Method. Nelle lingue che non supportano le funzioni virtuali private, il metodo template deve essere pubblico sebbene non sia realmente destinato a far parte dell'interfaccia.

+0

Se gli specificatori di accesso e la virtualità sono ortogonali, perché http://ideone.com/JjbVOP non riesce nella compilazione? La chiamata della funzione virtuale viene risolta in fase di runtime e non si compila il tempo, quindi cosa ho sbagliato nel mio programma? Non è possibile sovrascrivere i metodi virtuali protetti di classe Base per classe derivata? – Destructor

+0

@Distructor Questo errore di compilazione è dovuto al fatto che stai cercando di chiamare un metodo protetto di 'Parent' da' main() '. –

10

Questa è una pura funzione virtuale che sembra privata. Questo fa in modo che una classe derivata debba implementare il metodo. In questo caso Bar.

Penso che potresti essere confuso b/c questo è fatto per creare "interfacce" in C++ e molte volte le persone pensano che siano pubbliche. In alcuni casi è possibile definire un'interfaccia privata in cui un metodo pubblico utilizza tali metodi privati ​​per garantire l'ordine di come vengono chiamati.(Credo che questo è chiamato il Template Method)

per un tempo relativamente cattivo esempio :)

 
class RecordFile 
{ 
    public: 
     RecordFile(const std::string &filename); 

     void process(const Record &rec) 
     { 
      // Call the derived class function to filter out 
      // records the derived instance of this class does 
      // not care about 
      if (filterRecord(rec))  
      { 
       writeRecordToFile(rec);   
      } 
     }; 

    private: 
     // Returns true if the record is of importance 
     // and should be kept 
     virtual bool filterRecord(const Record &rec) = 0; 

     void writeRecordToFile(const Record &rec); 
}; 

+2

Non capisco, perché i metodi privati ​​non sono visibili nelle classi derivate. In che modo una classe derivata può sovrascrivere un metodo che non può "vedere", chiamare o accedere in alcun modo? – abelenky

+0

+1 - Hai fornito ragioni pratiche per l'argomento di Herb Sutter. –

+17

Abelenky, hai indicato la fonte principale di confusione riguardo ai virtual privati, ma il fatto è che non devi essere in grado di * chiamare * una funzione per poter * definirla *. Questo permette alla classe base di dire ai suoi discendenti: "Forniscimi una funzione, ma io solo deciderò quando chiamarla". –

9

ISO C++ 2003 consente esplicitamente:

§10.3 stati niente di accesso identificatore e contiene anche un nota nella seconda clausola secondo nel contesto di funzione virtuale sostituisce:

[...] controllo di ammissione (punto 11) è non considerata nella determinazione annullamento.

Il codice è completamente legale.

Problemi correlati