2012-01-23 27 views
16

consideri il seguente esempio:override una funzione membro con diverso tipo di ritorno

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     virtual int func() 
     { 
     cout << "vfunc in base class\n"; 
     return 0; 
     } 
}; 

class derived: public base 
{ 
    public: 
     double func() 
     { 
     cout << "vfunc in derived class\n"; 
     return 0; 
     } 
}; 

int main() 
{ 
    base *bptr = new derived; 
    bptr->func(); 

    return 0; 
} 

Il compilatore dà un errore per il codice precedente che c'è tipo conflitto per la funzione overriding. Perché non è possibile sovrascrivere una funzione nella classe derivata con un tipo di ritorno diverso?

Credo, in modo da ridefinire una funzione, il metodo virtuale classe base deve essere ridefinito nella classe derivata. Per ridefinire un metodo, le firme dei metodi devono essere le stesse. Dato che il tipo di reso non fa parte della firma, credo che anche se ci fosse una differenza nel tipo di ritorno, il metodo sarà comunque ridefinito? In questo caso per il codice sopra, la funzione virtuale func viene ridefinita nella classe derivata con un tipo di ritorno diverso. Ma il compilatore genera un errore. La mia comprensione è corretta?

+0

Per l'amor di chiarezza, quale compilatore sta dando voi quale errore? –

+0

@SionSheevok, GCC fa almeno: http://codepad.org/z7rXpCeK – bdonlan

+0

@SionSheevok: Sto usando gcc 3.4.6 –

risposta

17

Override significa essenzialmente che il metodo della classe Base o il metodo della classe Derivato verrà chiamato in fase di esecuzione a seconda dell'oggetto reale puntato dal puntatore .
implica che:
cioè: ogni luogo dove il metodo della classe base può essere chiamato può essere sostituito con chiamata al metodo della classe derivata, senza alcuna modifica il codice chiamante.

Per ottenere ciò, l'unico modo possibile è di restringere i tipi di restituzione dei metodi virtuali sovrascriventi per restituire lo stesso tipo della classe Base o un tipo derivato da quello (tipi di restituzione in co-variante) e gli Standard impone questa condizione.

Se la condizione di cui sopra non era a posto, lascerebbe una finestra per interrompere il codice esistente aggiungendo nuove funzionalità.

+2

Als: 'tipo derivato da quello (tipi di restituzione in co-variante)'. Questo è stato fondamentale per la mia comprensione. Bella spiegazione :) –

7

Per ridefinire una funzione virtuale, il valore restituito deve essere esattamente lo stesso *. C++ sarà non convertire automaticamente tra double e int qui - dopo tutto, come sarebbe sapere che tipo di ritorno che si desidera quando si chiama un puntatore classe derivata? Notare che se si modifica parte della firma (parametri, costanza, ecc.), È possibile modificare anche il valore di ritorno.

* - in senso stretto, deve essere "covariante". Ciò significa che il tipo che si restituisce deve essere un sottoinsieme del tipo di ritorno della funzione genitore. Ad esempio, se la classe padre restituisce un base *, è possibile restituire un derived *. Dal momento che derived s sono contemporaneamente anche base s, il compilatore consente di eseguire l'override in questo modo. Ma non è possibile restituire tipi completamente indipendenti come int e double; solo perché c'è una conversione implicita non significa che il compilatore ti permetterà di fare questo tipo di override.

+0

'Si noti che se si modifica parte della firma (parametri, costanza, ecc.), È possibile modificare anche il valore di ritorno'. Se lo faccio, la funzione non viene annullata, giusto? –

+3

Esattamente lo stesso o una sottoclasse, penso che tu intenda. I tipi di ritorno 'co-variante' – Nemo

+1

sono consentiti per le funzioni virtuali. –

1

Vedi this question. Per riassumere, puoi sostituire solo una funzione virtuale utilizzando un tipo di reso diverso se i tipi sono covariant.

+0

I * tipi * non sono covarianti, il * override * è. –

+0

Il howto I link ha la semantica sbagliata? – ezod

+0

No, solo la tua interpretazione è un po 'idiosincratica. –

0

Overriding non è posssible, come le firme sono diversi. Lo scopo principale dell'overriding è il polimorfismo ma non è possibile nell'esempio precedente

+1

Le firme sono le stesse qui. Le funzioni differiscono solo nel tipo restituito e il tipo restituito non fa parte della firma. –

+0

@LinuxPenseur grazie per averlo detto, questo è quello che intendevo dire – kvk

1

Se si desidera eseguire l'override, provare a utilizzare il modello.

vedere il seguente:

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     template<typename X> X func() 
     { 
     cout << "vfunc in base class\n"; 
     return static_cast<X>(0); 
     } 
};  

class derived: public base 
{ 
    public: 
     template<typename X> X func() 
     { 
     cout << "vfunc in derived class\n"; 
     return static_cast<X>(2); 
     } 
};  

int main() 
{ 
    derived *bptr = new derived; 
    cout << bptr->func<int>() << endl; 
    cout << dynamic_cast<base*>(bptr)->func<int>() << endl; 

    derived *bptr2 = new derived; 
    cout << bptr->func<double>() << endl; 
    cout << dynamic_cast<base*>(bptr)->func<int>() << endl; 


    return 0; 
} 

Naturalmente, non avete bisogno di dichiararlo su due differenti classi in questo modo, si potrebbe fare:

class base 
{ 
    public: 
     int func() 
     { 
     cout << "vfunc in base class\n"; 
     return 0; 
     } 

     double func(){ 
     cout << "vfunc for double class\n"; 
     return 2.; 

     } 
};