2010-12-24 14 views
5

Si consideri il seguente segmento di codice:Comportamento di oggetto C++ Riferimento

class Window // Base class for C++ virtual function example 
    { 
     public: 
      virtual void Create() // virtual function for C++ virtual function example 
      { 
       cout <<"Base class Window"<<endl; 
      } 
    }; 

    class CommandButton : public Window 
    { 
     public: 
      void Create() 
      { 
       cout<<"Derived class Command Button - Overridden C++ virtual function"<<endl; 
      } 
    }; 

    int main() 
    { 
     Window *button = new CommandButton; 
     Window& aRef = *button; 
     aRef.Create(); // Output: Derived class Command Button - Overridden C++ virtual function 
     Window bRef=*button; 
     bRef.Create(); // Output: Base class Window 

     return 0; 
    } 

Sia Aref e BREF vengono assegnati * pulsante, ma perché sono i due output diverso. Qual è la differenza tra l'assegnazione al tipo di riferimento e il tipo non di riferimento?

risposta

10

Si è verificato il problema dell'affettatura.

Window bRef =*button; 

Qui bRef non è un riferimento ma un oggetto. Quando assegni un tipo derivato su bRef, stai tagliando la parte derivata, lasciandoti solo con un oggetto Window costruito da un CommandButton.

Che cosa sta succedendo è che bRef viene creato nell'istruzione precedente utilizzando il costruttore di copie generato dal compilatore per la finestra di classe. Tutto ciò che fa questo costruttore è copiare gli elementi membri dal RHS all'oggetto appena costruito. Poiché la classe non contiene membri, non sta accadendo nulla.

Nota a margine: una classe con membri virtuali dovrebbe anche avere un distruttore virtuale.

+0

Quindi, con questa copia il costruttore in ritardo di associazione semplicemente non succede, giusto? –

+0

Gunner: Late Binding non è rilevante qui. Stai creando un nuovo oggetto tipizzato staticamente non un oggetto tipizzato dinamicamente (per questo hai bisogno di un riferimento o di un puntatore). –

+0

distruttore virtuale o protetto. In molti progetti le funzioni membro sono chiamate polimorficamente senza eliminare polimorficamente. –

2
Window bRef=*button; 
bRef.Create(); // Output: Base class Window 

Il tipo statico nonché dinamico di bRef è solo Window. Il meccanismo virtuale funziona solo con riferimenti e puntatori. bRef è un oggetto non un riferimento o un puntatore.

1
Window bRef=*button; 
bRef.Create(); // Output: Base class Window 

Qui bRef non è il riferimento a button (appena nominato così). bRef riceve solo il subobject di base che è Window.

+0

Ma qual è l'effetto di questo incarico che sto facendo. Poiché il pulsante * è stato inizializzato utilizzando CommandButton, non dovrebbe essere questo errore di compilazione? –

+0

No. La classe Window ha una finestra di costruzione copia (const window &). Poiché CommandButton è una finestra, può essere l'argomento di tale costruttore di copie. – cgmb

+0

@ Slavik81: Sì, allora? Come invalidare ciò che ho detto? – Nawaz

7
  • aRef ha Windowstatica tipo ma CommandButtondinamica tipo
  • bRef è semplicemente un oggetto di tipo Window (la CommandButton'parte' stato perso nella copia)

Questo è comunemente noto come object slicing un Di solito è impedito rendendo le classi di base astratte (fornendo una pura funzione virtuale) o non copiabili (ad esempio usando boost::noncopyable), perché entrambe le soluzioni renderebbero impossibile la compilazione del codice sulla riga Window& aRef = *button;.


Ora, perché fa bRef.Create() chiamata Window::Create? Bene, non c'è nient'altro che un quindi non c'è davvero molto di un'alternativa. Questo è essenzialmente come dichiarare un Window e chiamare Create su di esso: il fatto che bRef sia stato copiato da un'istanza CommandButton è irrilevante perché la porzione CommandButton è stata persa nella copia.

Proverò a rendere più chiaro citando lo standard (10.3/6):

[Nota: l'interpretazione della chiamata di una funzione virtuale dipende dal tipo di oggetto per il quale è chiamato (tipo dinamico), mentre l'interpretazione di una chiamata di una funzione membro non virtuale dipende solo sul tipo del puntatore o riferimento che indica tale oggetto (il tipo statico) (5.2.2). ]

Solo tramite puntatore o riferimento indiretto il tipo statico di un oggetto può essere diverso dal suo tipo dinamico.