2012-08-10 19 views
5

Vediamo questo codice:Come chiamare funzione virtuale della classe derivata tramite puntatore alla classe base

class CBase 
{ 
public: 
    virtual vfunc() { cout << "CBase::vfunc()" << endl; } 
}; 

class CChild: public CBase 
{ 
public: 
    vfunc() { cout << "CChild::vfunc()" << endl; } 
}; 

int main() 
{ 
CBase *pBase = new CBase; 
((CChild*)pBase)->vfunc(); // !!! important 
delete pBase; 
return 0; 
} 

L'output è:

CBase::vfunc() 

Ma io voglio vedere: CChild :: vfunc()

Explicit ((CChild *) pBase) consente di digitare "CChild *". Quindi, perché chiamare vfunc derivato() ho bisogno di sostituire stringa "importante" con: ((CChild *) pBase) -> CChild :: vfunc();

risposta

6

Non Funziona così - questo è:

CBase *pBase = new CChild; 
pBase->vfunc(); 

virtual chiamate di funzione vengono risolte in modo dinamico su puntatori & riferimenti (a meno che non si chiama il metodo in modo esplicito, come hai fatto). Il che significa che non importa cosa si dice al compilatore, il puntatore cercherà il metodo in vftable. Che, nel tuo caso, è il vftable di CBase.

5

Non è possibile. *pBase è un oggetto di tipo CBase. Non puoi trattarlo come se fosse un CChild perché non è un oggetto CChild.

L'utilizzo del puntatore ottenuto dal cast su CChild* causa il comportamento indefinito del programma.

+1

Quindi, come capire Schildt H .: "un puntatore di classe base può anche essere usato come puntatore a un oggetto di qualsiasi classe derivata da quella base". – LEXX

+0

E quindi perché la stringa ((CChild *) pBase) -> CChild :: vfunc() funziona? – LEXX

+0

@LEXX: in primo luogo, dovresti masterizzare quel libro e ottenere [un buon libro introduttivo] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Quello che dice in quella citazione è corretto, però. Un puntatore di classe base ('CBase *') può puntare a un oggetto di un tipo derivato da 'CBase' (come' CChild').Questo non è quello che hai fatto, però: il tuo puntatore di classe base punta ad un oggetto di classe base. Se si avesse, ad esempio, 'CBase * p = new CChild();', quindi 'p' sarebbe un puntatore di classe base che punta a un oggetto di una classe derivata. –

2

le altre risposte fanno punti importanti - per completare: se si può, infatti, avere a che fare con un CChild (ad esempio si tratta di un riferimento passato come parametro), quindi è possibile utilizzare per dynamic_cast abbattuto. tuttavia, l'elevato affidamento su dynamic_cast è spesso un'indicazione che il tuo progetto è andato storto.

dettagli sul cast può essere trovato qui: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

modo che il processo comporterebbe gettando il parametro CBase-CChild via dynamic_cast, se il riferimento è un CChild e dynamic_cast riesce, allora si potrebbe essere sicuro che siete occupandosi di un CChild e potreste quindi usarlo tranquillamente come CChild.

0

Il problema qui sembra molto semplice. CBase non può magicamente aggiornare a CChild! Fammi riscrivere il tuo esempio e aggiungere alcuni commenti. Dovrebbe essere autoesplicativo ...

#include <iostream> 

class CBase { 
public: 
    virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; } 
    virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise 
}; 

class CChild: public CBase { 
public: 
    void vfunc() { std::cout << "CChild::vfunc()" << std::endl; } 
    ~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor 
}; 

int main() 
{ 
    CBase *ptr1 = new CBase; 
    CBase *ptr2 = new CChild; 

    ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!! 
    ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase 

    delete ptr1; 
    delete ptr2; 
} 

uscita:

CBase::vfunc() 
CChild::vfunc() 

PS: Ho appena realizzato che sono circa 5 anni in ritardo alla festa, ma poiché trovo valore educativo su questo io' Lo pubblicherò comunque!

Problemi correlati