The C++ Compass

The C++ Compass
>FAQ<

FAQ

Home
Home

Risorse
Risorse

Utilities
Utilities

Compilatori
Compilatori

GUI Toolkits
GUI Toolkits

Libri
Libri

Download
Download

FAQ
FAQ



whoami
Who am I
[Precedente] [Indice] [Successiva]


[Classi]


Quando conviene usare una classe base virtuale ?

Sostanzialmente quando, in eredità multipla, si vuole una "identità" unica fra classi che se no sarebbero disparate.
Ecco un semplice esempio didattico basato sull'idioma "mix-in".
Supponiamo di avere una classe base astratta, tipo:

class emittore {
public:
 virtual void emetti(const std::string&) = 0;
};


le implementazioni di questa incapsulano il concetto di "emettere una riga" (magari la scrivono con iostream, magari la mandano ad un log di sistema, e/o la mostrano in una finestra su schermo, e così via).

Il modo più normale per connettere del codice "cliente" alla implementazione concreta di questa classe è passare al cliente un puntatore a emittore, a cui delegherà in modo esplicito l'output:

class chiaccherone {
 emittore* pEm;
public:
 chiacchierone(emittore* pEm): pEm(pEm) {}
 void parla() {
  pEm->emetti("Ciao!");
  // 998 linee omesse
  pEm->emetti("OK, basta.");
 }
};

da usarsi ad esempio con:
// si suppone: class emittore_su_stream: public emittore ...
emittore_su_stream ess(std::cout);
chiacchierone ciac(&ess);
ciac.parla();

Supponiamo, però, che per qualche buona e valida ragione scegliamo invece di fare la connessione con l'uso dell'eredità multipla.

Allora, dovremo usare emittore come base virtuale:

class emittore_su_stream: public virtual emittore { // ecc ecc
class chiacchierone_2: public virtual emittore {
public:
 void parla() {
  emetti("Ciao!");
  // 998 linee omesse
  emetti("OK, basta.");
 }
};

class cliente_connettore: public emittore_su_stream
  , public chiacchierone_2 {
public: cliente_connettore(std::iostream& x): emittore_su_stream(x) {}
};

Adesso, l'uso diverrà:
cliente_connettore x(std::cout);
x.parla();

Come vedi, l'eredità multipla (con base virtuale) ottiene risultati analoghi alla connessione esplicita ma con una fusione di identità fra 'cliente' dell'emittore (il 'chiacchierone') e 'servente' della stessa base astratta (l'emittore_su_stream).
Normalmente non è una gran bella alternativa perchè si riduce la flessibilità, ma a volte è proprio questo "fissaggio compile-time" quello che desideriamo (soprattutto se vogliamo parametrizzarlo in un template).

Che la base virtuale sia una base astratta pura (una "interfaccia", o come alcuni anche dicono [secondo me falsando un poco la terminologia più usuale] una "classe-protocollo") è molto tipico; è possibile costruire esempi in cui ha senso avere una base virtuale che non e` puramente astratta (sostanzialmente per una scelta di centralizzare uno "stato" -- ma normalmente, questo "stato" se ne starebbe meglio in una classe mixin, con i suoi accessori nella base astratta pura che fa da base virtuale), ma si tratta, così a ocio, di meno del 5-10% dei casi reali di uso di questo costrutto già un pò astruso.




Ultimo aggiornamento : 03/07/2000

email webmaster@thecppcompass.org