Cerca nel sito:
ricerca
avanzata

Frasi Celebri...

Il dentista ? un prestigiatore che, dopo aver messo del metallo nella tua bocca, tira fuori monete dalle tue tasche.

Ambrose Gwinnett Bierce 

Sondaggio:

Quale tra queste ? la pi? bella?

Monica Bellucci
Jennifer Lopez
Paola Barale
Selen
Sabrina Ferilli
Luisa Corna
Laura Freddi
Susanna Messaggio

visualizza risultati


 

Ereditarieta` multipla

 

Implicitamente e` stato supposto che una classe potesse essere derivata solo da una classe base, in effetti questo e` vero per molti linguaggi, tuttavia il C++ consente l'ereditarieta` multipla. In questo modo e` possibile far ereditare ad una classe le caratteristiche di piu` classi basi, un esempio e` dato dall'implementazione della libreria per l'input/output di cui si riporta il grafo della gerarchia (in alto le classi basi, in basso quelle derivate):




come si puo` vedere esistono diverse classi ottenute per ereditarieta` multipla, iostream ad esempio che ha come classi basi istream e ostream.
La sintassi per l'ereditarieta` multipla non si discosta da quella per l'ereditarieta` singola, l'unica differenza e` che bisogna elencare tutte le classi basi separandole con virgole; al solito se non specificato diversamente per default l'ereditarieta` e` privata. Ecco un esempio tratto dal grafo precedente:


  class iostream : public istream, public ostream {
    /* ... */
  };


L'ereditarieta` multipla comporta alcune problematiche che non si presentano in caso di ereditarieta` singola, quella a cui si puo` pensare per prima e` il caso in cui le stesse definizioni siano presenti in piu` classi base (name clash):


  class BaseClass1 {
    public:
      void Foo();
      void Foo2();
      /* ... */
  };

  class BaseClass2 {
    public:
      void Foo();
      /* ... */
  };

  class Derived : BaseClass1, BaseClass2 {
    // Non ridefinisce Foo()
    /* ... */
  };


La classe Derived eredita piu` volte gli stessi membri e in particolare la funzione Foo(), quindi una situazione del tipo


  Derived A;
  /* ... */
  A.Foo()      // Errore, e` ambiguo!


non puo` che generare un errore perche` il compilatore non sa a quale membro si riferisce l'assegnamento. Si noti che l'errore viene segnalato al momento in cui si tenta di chiamare il metodo e non al momento in cui Derived eredita, il fatto che un membro sia ereditato piu` volte non costituisce di per se alcun errore.
Rimane comunque il problema di eliminare l'ambiguita` nella chiamata di Foo(), la soluzione consiste nell'utilizzare il risolutore di scope indicando esplicitamente quale delle due Foo():


  Derived A;
  /* ... */
  A.BaseClass1::Foo()      // Ok!


in questo modo non esiste piu` alcuna ambiguita`.
Alcune osservazioni:

  1. quanto detto vale anche per i membri dato;

  2. non e` necessario che la stessa definizione si trovi in piu` classi basi dirette, e` sufficiente che essa giunga alla classe derivata attraverso due classi basi distinte, ad esempio (con riferimento alla precedenti dichiarazioni):

    
      class FirstDerived : public BaseClass2 {
        /* ... */
      };
    
      class SecondDerived : public BaseClass1,
                            public FirstDerived {
        /* ... */
      };
    

    Nuovamente SecondDerived presenta lo stesso problema, e` cioe` sufficiente che la stessa definizione giunga attraverso classi basi indirette (nel precedente esempio BaseClass2 e` una classe base indiretta di SecondDerived);

  3. il problema non si sarebbe posto se Derived avesse ridefinito la funzione membro Foo().

Il problema diviene piu` grave quando una o piu` copie della stessa definizione sono nascoste dalla keyword private nelle classi basi (dirette o indirette), in tal caso la classe derivata non ha alcun controllo su quella o quelle copie (in quanto vi accede indirettamente tramite le funzioni membro ereditate) e il pericolo di inconsistenza dei dati diviene piu` grave.

 

successivo
–«  INDICE  »–

 

 

 

 

 
Powered by paper&pencil (carta&matita ) - Copyright © 2001-2019 Cataldo Sasso