2014-09-23 10 views
6

header.hRisoluzione di funzione virtuale con parametri di default

#include <iostream> 
using namespace std; 
class A 
{ 
    public: 
     virtual void display(int i=5) { cout<< "Base::" << i << endl; } 
}; 

class B : public A 
{ 
    public: 
     void display(int i=9) { cout<< "Derived::" << i << endl; } 
}; 

source.h

#include <iostream> 
#include "header.h" 
using namespace std; 
int main() 
{ 
    A * a = new B(); 
    a->display(); 

    A* aa = new A(); 
    aa->display(); 

    B* bb = new B(); 
    bb->display(); 
} 

uscita

Derived::5 
Base::5 
Derived::9 

mia comprensione le funzioni dei parametri di default sono state risolte durante la compilazione utilizzando l'overloading delle funzioni. Le funzioni virtuali sono state quindi risolte durante il runtime mediante l'override della funzione.

Ma quello che sta succedendo è un casino.
Come si verifica effettivamente la risoluzione della funzione qui?

+1

'risoluzione argomento predefinito si basa sul tipo statico dell'oggetto attraverso il quale si chiama il function' (cioè in base al tipo di puntatore). http://social.msdn.microsoft.com/Forums/en-US/90b9b8ee-ed5f-4ba8-93b5-612c4d906124/default-argument-and-inheritance-hierarchy –

+0

Nota che puoi ovviare a questo problema sovraccaricando il virtuale funziona con un'altra funzione virtuale senza il parametro, che "inoltra" a quella con il parametro.Come: in Base 'virtual void display() {display (9); } 'e in Derived' void display() {display (5); } ' – leemes

risposta

7

Il codice è in realtà visto dal compilatore in questo modo:
(Il metodo display() non è in realtà lì, ma le opere risolvere in modo simile)

class A 
{ 
public: 
    virtual void display(int i) { cout<< "Base::" << i << endl; } 
    void display() { display(5); } 
}; 

class B : public A 
{ 
public: 
    void display(int i) override { cout<< "Derived::" << i << endl; } 
    void display() { display(9); } 
}; 

Ora si deve capire cosa succede. Sei chiamando il il numero non virtuale display() che chiama la funzione virtuale. In parole più rigide: l'argomento predefinito viene risolto proprio come se il metodo no-arg non-virtuale fosse presente - dal tipo della variabile (non dal tipo effettivo dell'oggetto), ma il codice viene eseguito in base al tipo oggetto reale, poiché è metodo virtuale:

int main() 
{ 
    A * a = new B(); // type of a is A* real type is B 
    a->display(); // calls A::display() which calls B::display(5) 

    A* aa = new A(); // type of aa is A* real type is A 
    aa->display(); // calls A::display() which calls A::display(5) 

    B* bb = new B(); // type of bb is B* real type is B 
    bb->display(); // calls B::display() which calls B::display(9) 
} 
+0

Oh, questo è esattamente quello che stavo cercando.Hey, ma allora come viene stampato 'Derived :: 5'? Dovrebbe essere 'Base :: 5' – cppcoder

+0

Quando invochi' a-> display(); 'su un oggetto di tipo (dinamico)' B', chiama 'display();', questo è il ** non- sovraccarico virtuale ** 'display()' che chiama 'display (5);' che è quindi ** virtualmente ** risolto in 'B :: display (5)'. E nel codice originale succede qualcosa di simile. Invece della funzione non virtuale aggiuntiva, è il parametro predefinito che viene risolto sul ** tipo statico **. – leemes

+1

Hmm, questo è complicato. – cppcoder

7

Non esiste alcun polimorfismo sugli argomenti predefiniti. Sono risolti in fase di compilazione.

A::display ha argomento di default pari 5. B::display ha argomento di default pari 9. E 'solo il tipo di a, aa, bb variabili che conta.

L'utilizzo di diversi argomenti predefiniti nei metodi polimorfici è fonte di confusione e deve essere evitato.

+0

Mi dispiace ma non capisco: perché' a-> display() 'mostra' Derived :: 5' e 'bb-> display()' mostra 'Derived :: 9'? Sono definiti esattamente nello stesso modo ... –

+2

@StefanoF Perché 'a' è di tipo' A * 'mentre' bb' è di tipo 'B *'. Quindi, 'a-> display()' usa la dichiarazione di 'classe A' mentre' bb-> ​​display() 'usa quello di' classe B' –

5

Questo comportamento è specificato in Capitolo 8.3.6: impostazione predefinita argomenti entro Programming languages — C++ (ISO/IEC 14882:2003(E)):

una chiamata di funzione virtuale (10.3) usi l'argomento predefinito nti nella dichiarazione della funzione virtuale determinata dal tipo statico del puntatore o riferimento denotano l'oggetto