2009-09-10 29 views
20

Mi aspetto che se foo viene dichiarato nella classe D, ma non contrassegnato come virtuale, il codice seguente chiamerebbe l'implementazione di foo in D (indipendentemente dal tipo dinamico di d).In C++, una funzione è automaticamente virtuale se sovrascrive una funzione virtuale?

D& d = ...; 
d.foo(); 

Tuttavia, nel seguente programma, questo non è il caso. Qualcuno può spiegarlo? Un metodo è automaticamente virtuale se sovrascrive una funzione virtuale?

#include <iostream> 

using namespace std; 

class C { 
public: 
     virtual void foo() { cout << "C" << endl; } 
}; 

class D : public C { 
public: 
     void foo() { cout << "D" << endl; } 
}; 

class E : public D { 
public: 
     void foo() { cout << "E" << endl; } 
}; 

int main(int argc, char **argv) 
{ 
     E& e = *new E; 
     D& d = *static_cast<D*>(&e); 
     d.foo(); 
     return 0; 
} 

L'uscita del programma di cui sopra è:

E 
+4

Lo static_cast è superfluo - 'D & D = * static_cast (&e);' è equivalente a 'D & d = e;' dovuto al cast implicito da E */E & D */D &. –

+0

In C++ 11 l'aggiunta di "override" alla dichiarazione della funzione rende chiaro l'intento di sovrascrivere la funzione della classe base, inoltre attiva un errore dal compilatore nel caso in cui la funzione dichiarata differisca in constness dalla base (qualcosa che possa vi sorprendete nel caso in cui derivate da std :: exception per esempio e dichiarate what() non-const) – Ghita

risposta

22

standard 10.3.2 (class.virtual) dice:

Se una funzione membro virtual vf è dichiarato in una classe base e in una classe derivata, derivata direttamente o indirettamente da Base, una funzione membro vf con lo stesso nome e lo stesso elenco di parametri di Base :: vf è dichiarato, quindi Derived :: vf è anche virtuale (indipendentemente dal fatto che sia dichiarato) e sostituisce *

[Nota: una funzione con lo stesso nome ma una lista di parametri diversa (clausola sopra) come una funzione virtuale non è necessariamente virtuale e non sovrascrive. L'uso dello specificatore virtuale nella dichiarazione di una funzione di override è legale ma ridondante (ha una semantica vuota). Il controllo di accesso (clausola class.access) non è considerato nel determinare l'override. --- end foonote]

17

risposta rapida può essere, ma la risposta corretta è

C++ non conosce la funzione nascondiglio, così ignorando funzione virtuale senza segni di parole chiave virtuali che svolgono anche funzione virtuale.

+11

@Yossarian, ecco perché è considerata una buona pratica dichiarare le funzioni virtuali nelle classi derivate come virtuali in modo che l'intento sia chiaro. discute questo nel suo libro Effective C++. –

+0

Ho sentito da qualche parte che non contrassegnare virtuale nei metodi derivati ​​li renderebbe virtualmente definitivi. che rende il derivato di terzo livello un override non virtuale. ma trovo che l'estratto standard di Tadeusz stia dimostrando questa convinzione errata a causa della parola "indirettamente", non è vero? –

+2

@ v.oddou "Ho sentito da qualche parte" che le cose che le persone hanno "sentito da qualche parte" sono solitamente false. ;-) Finché esiste una funzione con la stessa firma contrassegnata come 'virtuale' _somewhere_ più in alto nella gerarchia, quindi qualsiasi funzione derivata con la stessa firma è un override. Gli "spazi vuoti" nel fatto che la dichiarazione includesse 'virtuale' non sono rilevanti, poiché, di nuovo, la parola chiave ha una semantica vuota dopo il suo aspetto più basale. –

0

Non si sta creando alcuna copia dell'oggetto di e e inserendolo in d. Quindi d.foo() segue il normale comportamento polimorfico e chiama il metodo di classe derivato. Un metodo dichiarato come virtuale nella classe base diventa automaticamente virtuale anche nella classe derivata.

-1

L'uscita ("E") si comporta esattamente come ci si aspetterebbe che si comporti.

Il motivo: Il tipo dinamico (cioè di runtime) di tale riferimento è E. Si sta eseguendo un upcast statico a D, ma ciò non cambia il tipo effettivo dell'oggetto, naturalmente.

Questa è l'idea alla base dei metodi virtuali e delle spedizioni dinamiche: si vede il comportamento del tipo di istanza che si sta creando, che è E, in questo caso.

Problemi correlati