Chiamata alla definizione della classe base della funzione membro virtuale con puntatore a funzione
-
05-07-2019 - |
Domanda
Voglio chiamare l'implementazione della classe base di una funzione virtuale usando un puntatore alla funzione membro.
class Base {
public:
virtual void func() { cout << "base" << endl; }
};
class Derived: public Base {
public:
void func() { cout << "derived" << endl; }
void callFunc()
{
void (Base::*fp)() = &Base::func;
(this->*fp)(); // Derived::func will be called.
// In my application I store the pointer for later use,
// so I can't simply do Base::func().
}
};
Nel codice sopra l'implementazione della classe derivata di func verrà chiamata da callFunc. C'è un modo in cui posso salvare un puntatore alla funzione membro che punta a Base :: func, o dovrò usare usando
in qualche modo?
Nella mia attuale applicazione uso boost :: bind per creare un oggetto boost :: function in callFunc che successivamente userò per chiamare func da un'altra parte del mio programma. Quindi, se boost :: bind o boost :: function hanno un modo per aggirare questo problema, che potrebbe anche aiutare.
Soluzione
Quando si chiama un metodo virtuale tramite un riferimento o un puntatore, si attiva sempre il meccanismo di chiamata virtuale che trova il tipo più derivato.
La soluzione migliore è aggiungere una funzione alternativa che non sia virtuale.
Altri suggerimenti
Purtroppo non è possibile quello che stai cercando di fare. Le funzioni da puntatore a membro sono progettate per mantenere la virtualità della funzione indicata.
Il tuo problema è che un puntatore a funzione membro non è esattamente lo stesso di un puntatore a funzione nuda. In realtà non è solo un puntatore, ma una una struttura notevolmente più complessa , che varia nei dettagli a livello dell'implementazione del compilatore. Quando lo invochi tramite la sintassi (this- > * fp) ()
, in realtà lo stai chiamando sull'oggetto originale, che causa l'invio di una funzione virtuale.
Una cosa che potrebbe funzionare è lanciarlo su un tipo di puntatore non di metodo. Questo è un po 'scricchiolante ma penso dovrebbe funzionare. Devi ancora passare un Base *
ma lo fai esplicitamente e l'invio della funzione virtuale viene ignorato:
typedef void BasePointer(Base*);
void callFunc()
{
BasePointer fp = (BasePointer *)&Base::func;
fp(this);
}
Aggiornamento: Ok, no, non puoi farlo in questo modo. È illegale e non sarebbe sicuro se fosse legale. Le FAQ su C ++ ha altro su questo . Ma sapere che non risolve il tuo problema. Il problema è che, puntatore a oggetto o puntatore a membro se si desidera chiamare Base :: func
tramite un puntatore Base
, l'oggetto che sta puntando deve anche essere un Base
. Se riesci a sistemarlo, puoi usare un puntatore alla funzione membro.
Ecco un altro pensiero, non carino, ma almeno praticabile. Fornire una funzione in Derivato
, non virtuale, che chiama esplicitamente Base :: func
. Indica invece quello. Non si ridimensionerà se è necessario farlo nel caso generale di molte varianti diverse di func
e callFunc
, ma funzionerà bene per un metodo.
C'è qualche motivo specifico per farlo tramite un puntatore a funzione?
Dovresti essere in grado di scrivere semplicemente:
Base::func();
per chiamare l'implementazione della classe base.
Oltre a ciò che dice il quark, un'osservazione più generale è che dovresti usare un'implementazione di segnale / slot anziché un puntatore a funzione nuda. Boost ne ha uno, c'è libsigc e molti altri.
Cosa c'è che non va?
(Base(*this).*fp)();
Ora, se sei soddisfatto, solleva la questione del perché stai persino utilizzando un puntatore a funzione. Penso che un po 'più di contesto potrebbe aiutare.