2010-04-09 19 views
38

Recentemente sono venuto a sapere che in C++ le funzioni virtuali pure possono avere facoltativamente un corpo.Casi d'uso di funzioni virtuali pure con il corpo?

Quali sono i casi di utilizzo del mondo reale per tali funzioni?

+2

sembra un dupe di http://stackoverflow.com/questions/2089083/pure-virtual-function-with-implementation – patros

+5

@patros: nessuna delle risposte in quella discussione descrive un * caso d'uso * reale *. Quindi, no, non penso che questo sia un errore. – missingfaktor

risposta

31

Il classico è un distruttore virtuale pura:

class abstract { 
    public: 
    virtual ~abstract() = 0; 
}; 

abstract::~abstract() {} 

Si rendono puro perché non c'è niente altro da fare così, e si desidera la classe di essere astratto, ma è necessario fornire un'implementazione comunque, perché i distruttori delle classi derivate chiamano il tuo esplicitamente. Sì, lo so, un esempio da manuale piuttosto sciocco, ma in quanto tale è un classico. Deve essere stato nella prima edizione di The C++ Programming Language.

In ogni caso, non ricordo di aver mai davvero bisogno della capacità di implementare una pura funzione virtuale. A me sembra che l'unica ragione per cui ci sia questa caratteristica è che avrebbe dovuto essere esplicitamente disabilitato e Stroustrup non ne vedeva una ragione.

Se pensi di aver bisogno di questa funzione, probabilmente sei sulla strada sbagliata con il tuo progetto.

+3

Un problema che un down - put potrebbe avere (per la cronaca, non ho fatto downvote) è che non c'è davvero una forte ragione per avere un distruttore virtuale puro. Se c'è un'altra pura funzione virtuale, non c'è motivo per il dtor di essere virtuale puro (anche se quasi certamente dovrebbe essere virtuale).Se il dtor è l'unica funzione pura virtuale, allora potrebbe non esserci davvero bisogno che la classe sia astratta. –

+1

@ Michael: conosco questa critica. (In effetti, ho scritto più o meno questo nella mia risposta.) Il problema è che non riesco a pensare a nessuna buona ragione per implementare una pura funzione virtuale da solo. Come ho scritto, se ritieni di aver bisogno di farlo, è probabile che tu sia sulla strada sbagliata. – sbi

+0

@MichaelBurr è ridicolo. dimentica tutte le altre cose che non sono metodi. puoi avere una classe astratta di base che ti dà alcuni campi dati (perché perché duplicati quando saranno condivisi da derivati) e dichiarare un'interfaccia o un concetto allo stesso tempo. –

27

Le funzioni virtuali pure con o senza corpo significano semplicemente che i tipi derivati ​​devono fornire la propria implementazione.

I corpi funzione virtuali puri nella classe base sono utili se le classi derivate desiderano chiamare l'implementazione della classe base.

8

Un caso d'uso chiama la funzione virtuale pura dal costruttore o dal distruttore della classe.

+1

+1: questo è in effetti il ​​caso principale. Qualcuno potrebbe dire l'unico caso. –

+0

Ma non esiste un costruttore virtuale puro, che il tuo post sembra implicare. –

+3

@ John: l'ho letto diverso. Tuttavia, penso che chiamare funzioni virtuali, pure o meno, da cori o detors sia comunque una pratica piuttosto discutibile. – sbi

4

L'unica differenza della funzione virtuale con il corpo e la pura funzione virtuale con il corpo è che l'esistenza del secondo impedisce l'istanziazione. Non è possibile contrassegnare l'abstract della classe in C++.

16

Una ragione per cui una classe di base astratta (con una funzione virtuale pura) potrebbe fornire un'implementazione per una pura funzione virtuale che dichiara è quella di consentire alle classi derivate di avere un semplice 'predefinito' che possono scegliere di utilizzare. Non c'è un grande vantaggio su una normale funzione virtuale che può essere sovrascritta facoltativamente - in effetti, l'unica vera differenza è che si sta costringendo la classe derivata ad essere esplicita sull'uso dell'implementazione di classe base 'predefinita' :

class foo { 
public: 
    virtual int interface(); 
}; 

int foo::interface() 
{ 
    printf("default foo::interface() called\n"); 
    return 0; 
}; 


class pure_foo { 
public: 
    virtual int interface() = 0; 
}; 

int pure_foo::interface() 
{ 
    printf("default pure_foo::interface() called\n"); 
    return 42; 
} 

//------------------------------------ 

class foobar : public foo { 
    // no need to override to get default behavior 
}; 

class foobar2 : public pure_foo { 
public: 
    // need to be explicit about the override, even to get default behavior 
    virtual int interface(); 
}; 

int foobar2::interface() 
{ 
    // foobar is lazy; it'll just use pure_foo's default 
    return pure_foo::interface(); 
} 

non sono sicuro che ci sia un sacco di benefici - forse nei casi in cui un progetto iniziato con una classe astratta, poi nel corso del tempo ha scoperto che molte delle classi concrete derivate stavano attuando lo stesso comportamento , quindi hanno deciso di spostare tale comportamento in un'implementazione di classe base per la pura funzione virtuale.

Suppongo che potrebbe anche essere ragionevole inserire un comportamento comune nell'implementazione della classe base della pura funzione virtuale che le classi derivate potrebbero modificare/migliorare/aumentare.

+0

@RichardGeorge: puoi spiegare cosa non sta funzionando correttamente? Funziona come mi aspetto, ma forse stai guardando un caso d'uso diverso da me. –

+0

@Micheal, funziona bene, ho un po 'incasinato con il mio caso d'uso, +1 per te. –

7

L'onnipotente Herb Sutter, ex presidente del comitato standard C++, did give 3 scenarios in cui è possibile considerare l'implementazione di metodi puramente virtuali.

Devo dire che personalmente - non trovo nessuno di loro convincente, e in genere considerarlo come una delle verruche semantiche del C++.Sembra che C++ faccia di tutto per costruire e distruggere vtables di genitori astratti, che li esponga brevemente solo durante la costruzione/distruzione del figlio, and then gli esperti della comunità raccomandano all'unanimità never to use them.

+1

L'articolo di Sutter è eccellente. Ho chiarito alcune idee oscure per me. – DarenW

+0

Non vedo la relazione con i vtables del genitore astratto. – curiousguy

2

Questa domanda può davvero creare confusione nell'apprendimento di OOD e C++. Personalmente, una cosa che mi veniva costantemente in mente era qualcosa come: Se avessi bisogno di una funzione Pure Virtual per avere anche un'implementazione, quindi perché renderla "Pure" al primo posto? Perché non lasciarlo solo "Virtuale" e ne hanno derivato entrambi i benefici e scavalcare l'implementazione di base?

La confusione giunge al fatto che molti sviluppatori considerano l'assenza di corpo/implementazione come l'obiettivo/beneficio principale della definizione di una funzione virtuale pura. Questo non è vero! Nella maggior parte dei casi, l'assenza di corpo è una conseguenza logica di una pura funzione virtuale. Il principale vantaggio di avere una pura funzione virtuale è DEFINIRE UN CONTRATTO! Definendo una pura funzione virtuale, si desidera che FORCE ogni derivato di SEMPRE fornisca la PROPRIA IMPLEMENTAZIONE della funzione. Questo "aspetto CONTRATTUALE" è molto importante soprattutto se stai sviluppando qualcosa come un'API pubblica. Rendere la funzione solo virtuale non è sufficiente perché i derivati ​​non sono più costretti a fornire la propria implementazione, quindi si può perdere l'aspetto del contratto (questo può essere limitato nel caso di un'API pubblica). Come comunemente detto: "Le funzioni virtuali possono essere sovrascritte, le funzioni Pure Virtual DEVONO essere annullate." E nella maggior parte dei casi, i contratti sono concetti astratti quindi non ha senso per le corrispondenti funzioni virtuali pure avere qualsiasi implementazione.

Ma a volte, e poiché la vita è strana, è possibile che si desideri stabilire un contratto forte tra i derivati ​​e si desidera inoltre che beneficino in qualche modo di un'implementazione predefinita, specificando il proprio comportamento per il contratto. Anche se la maggior parte degli autori di libri consiglia di evitare di entrare in queste situazioni, la lingua necessaria per fornire una rete di sicurezza per prevenire il peggio! Una semplice funzione virtuale non sarebbe sufficiente poiché potrebbe esserci il rischio di fuggire dal contratto. Pertanto, la soluzione fornita da C++ consentiva alle funzioni virtuali pure di fornire un'implementazione predefinita.

L'articolo Sutter sopra citato fornisce interessanti casi di utilizzo di funzioni Pure Virtual con corpo.

+0

Dov'è l'articolo di Sutter? Non lo vedo oltre alla tua osservazione nella frase finale * "... l'articolo di Sutter citato sopra ..." *. – jww

Problemi correlati