In C ++, una funzione è automaticamente virtuale se sostituisce una funzione virtuale?

StackOverflow https://stackoverflow.com/questions/1404797

  •  05-07-2019
  •  | 
  •  

Domanda

Mi aspetto che se foo viene dichiarato nella classe D , ma non contrassegnato come virtuale, il seguente codice chiamerebbe l'implementazione di foo in D (indipendentemente dal tipo dinamico di d ).

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

Tuttavia, nel seguente programma, non è così. Qualcuno può spiegare questo? Un metodo è automaticamente virtuale se sostituisce 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'output del programma sopra è:

E
È stato utile?

Soluzione

Lo standard 10.3.2 (class.virtual) dice:

  

Se una funzione membro virtuale vf viene dichiarata in una classe Base e in una classe Derivata, derivata direttamente o indirettamente da Base, viene dichiarata una funzione membro vf con lo stesso nome e lo stesso elenco di parametri di Base :: vf, quindi Derivata :: vf è anche virtuale (indipendentemente dal fatto che sia così dichiarato) e ignora *

     

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

Altri suggerimenti

La risposta rapida potrebbe essere no, ma la risposta corretta è

Il C ++ non sa come nascondere le funzioni, quindi sovrascrivendo la funzione virtuale senza segni di parole chiave virtuali che funzionano anche in modo virtuale.

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

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

Il motivo: Il tipo dinamico (ovvero runtime) di quel riferimento è E. Stai facendo un upcast statico su D, ma questo non cambia il tipo reale dell'oggetto ovviamente.

È proprio questa l'idea alla base dei metodi virtuali e degli invii dinamici: vedi il comportamento del tipo che stavi istanziando, che è E, in questo caso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top