Chiamata alla definizione della classe base della funzione membro virtuale con puntatore a funzione

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

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.

È stato utile?

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.

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