Appel de la définition de classe de base de la fonction membre virtuelle avec un pointeur de fonction

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

Question

Je souhaite appeler l'implémentation de classe de base d'une fonction virtuelle à l'aide d'un pointeur de fonction membre.

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().
    }
};

Dans le code ci-dessus, l'implémentation de classe dérivée de func sera appelée à partir de callFunc. Existe-t-il un moyen de sauvegarder un pointeur de fonction membre pointant sur Base :: func ou devrai-je utiliser en utilisant d'une manière ou d'une autre?

Dans mon application actuelle, j'utilise boost :: bind pour créer un objet boost :: function dans callFunc, que j'utilise par la suite pour appeler func depuis une autre partie de mon programme. Donc, si boost :: bind ou boost :: function ont un moyen de contourner ce problème, cela aidera également.

Était-ce utile?

La solution

Lorsque vous appelez une méthode virtuelle via une référence ou un pointeur, vous activez toujours le mécanisme d'appel virtuel qui recherche le type le plus dérivé.

Votre meilleur choix est d'ajouter une fonction alternative non virtuelle.

Autres conseils

Malheureusement, ce que vous essayez de faire n’est pas possible. Les fonctions de pointeur à membre sont conçues pour préserver le caractère virtuel de la fonction pointée.

Votre problème est qu'un pointeur de fonction membre n'est pas tout à fait la même chose qu'un pointeur de fonction nue. En réalité, il ne s’agit pas simplement d’un pointeur, mais d’une structure considérablement plus complexe , qui varie dans ses détails au niveau de l’implémentation du compilateur. Lorsque vous l'appelez via la syntaxe (this- > * fp) () , vous l'appelez en fait sur l'objet d'origine, ce qui entraîne la répartition de la fonction virtuelle.

Une chose qui pourrait fonctionner est de le convertir en un type de pointeur non-méthode. C’est un peu grinçant mais je pense que cela devrait fonctionner. Vous devez toujours transmettre un Base * , mais vous le faites explicitement et la répartition de la fonction virtuelle est contournée:

typedef void BasePointer(Base*);

void callFunc()
{
    BasePointer fp = (BasePointer *)&Base::func;
    fp(this);
}

Mise à jour: OK, non, vous ne pouvez pas le faire de cette façon. C'est illégal et ce ne serait pas sûr si c'était légal. La FAQ C ++ a pour plus d'informations à ce sujet . Mais savoir que cela ne résout pas votre problème. Le problème est que, pointeur vers objet ou pointeur vers membre si vous souhaitez appeler Base :: func via un pointeur Base , l'objet qu'il pointe doit être aussi être un Base . Si vous pouvez organiser cela, vous pouvez utiliser un pointeur de fonction membre.

Voici une autre pensée, pas jolie, mais au moins réalisable. Fournissez une fonction dans Derived , non virtuelle, qui appelle explicitement Base :: func . Pointez sur cela à la place. Cela ne sera pas mis à l'échelle si vous devez le faire dans le cas général de nombreuses variantes différentes de func et de callFunc , mais cela fonctionnera correctement pour une méthode.

Existe-t-il une raison spécifique pour ce faire via un pointeur de fonction?

Vous devriez pouvoir simplement écrire:

Base::func();

pour appeler l'implémentation de la classe de base.

En plus de ce que dit Quark, une remarque plus générale est que vous devez utiliser une implémentation de signal / emplacement plutôt qu'un pointeur de fonction nue. Boost en a un, il y a libsigc et beaucoup d'autres.

Qu'est-ce qui ne va pas avec ça?

(Base(*this).*fp)();

Maintenant, si cela vous satisfait, cela soulève la question de savoir pourquoi vous utilisez même un pointeur de fonction en premier lieu. Je pense qu'un peu plus de contexte pourrait aider.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top