C++ héritages et pointeurs de fonction de membre

en C++, Les pointeurs de fonction de membre peuvent-ils être utilisés pour pointer vers des membres de classe dérivés (ou même de base)?

modifier: Peut-être un exemple de l'aide. Supposons que nous ayons une hiérarchie de trois classes X,Y, Z par ordre d'héritage. Y a donc une classe de base X et une classe dérivée Z.

maintenant nous pouvons définir un pointeur de fonction membre p pour la classe Y. C'est écrit comme suit:

void (Y::*p)();

(pour la simplicité, Je suppose que nous sommes seulement intéressés par les fonctions avec la signature void f() )

pointeur p peut maintenant être utilisé pour pointer vers des fonctions membres de la classe Y.

Cette question (deux questions) est alors:

  1. p être utilisée pour pointer vers une fonction dans la classe dérivée Z?
  2. p être utilisée pour pointer vers une fonction dans la classe de base X?
43
demandé sur smh 2008-09-13 01:24:53

8 réponses

C++03 std, §4.11 2 pointeur sur les conversions de membres:

Une rvalue de type "pointeur sur membre B de type cv T, "où B est un type de classe, peut être converti en pointeur de valeur de type" à membre de D de type cv T, " où D est une classe dérivée (clause 10) de B. Si B est une classe de base inaccessible (clause 11), ambiguë (10.2) ou virtuelle (10.1) de D, UN programme qui nécessite cette conversion est mal formé. Le résultat de la conversion se réfère au même membre que le pointeur à membre avant la conversion a eu lieu, mais il se réfère au membre de la classe de base comme s'il était un membre de la classe dérivée. Le résultat Se réfère au membre dans l'instance de D DE B. puisque le résultat a le type " pointeur vers le membre de D de type cv T", il peut être déréférencé avec un D objet. Le résultat est le même que si le pointeur de membre de B était déréférencé avec le sous-objet de B de D. le pointeur de membre nul la valeur est convertie en valeur de pointeur de membre nul du type de destination. 52)

52)la règle pour la conversion des pointeurs en membres (de pointeur en Membre de base en pointeur en Membre de dérivé) semble inversée par rapport à la règle pour les pointeurs aux objets (de pointeur en dérivé à pointeur en base) (4.10, clause 10). Cette inversion est nécessaire pour assurer la sécurité du type. Note qu'un pointeur de membre n'est pas un pointeur vers un objet ou un pointeur vers la fonction et les règles pour les conversions de tels pointeurs ne s'appliquent pas aux pointeurs vers les membres. En particulier, un pointeur vers un membre ne peut pas être converti en un vide*.

en bref, vous pouvez convertir un pointeur en un membre d'une classe de base non-virtuelle accessible en un pointeur vers un membre d'une classe dérivée aussi longtemps que le membre n'est pas ambigu.

class A {
public: 
    void foo();
};
class B : public A {};
class C {
public:
    void bar();
};
class D {
public:
    void baz();
};
class E : public A, public B, private C, public virtual D {
public: 
    typedef void (E::*member)();
};
class F:public E {
public:
    void bam();
};
...
int main() {
   E::member mbr;
   mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
   mbr = &C::bar; // invalid: C is private 
   mbr = &D::baz; // invalid: D is virtual
   mbr = &F::bam; // invalid: conversion isn't defined by the standard
   ...

Conversion dans l'autre sens (via static_cast) est régi par § 5.2.9 9:

Une rvalue de type "pointeur sur membre des D de type cv1 T" peut être converti en valeur de type "pointeur vers membre de type B cv2 T", Où B est une classe de base (clause 10 classe.dérivée) de D, si une conversion standard de "pointeur sur membre B de type T" à "pointeur de membre de D de type T" existe (4.11 conv.mem) et cv2 est le même cv-qualification, ou plus cv-qualification que,cv1. 11) le pointeur de membre nul (4.11 conv.mem) est convertie en pointeur de membre nul du type de destination. Si la classe B contient le membre d'origine, ou une base ou d'une classe dérivée de la classe contenant l'origine, le pointeur résultant pour les points des membres à l'origine. Sinon, le résultat de la fonte n'est pas défini. [Note: bien que la Classe B ne doive pas nécessairement contenir le membre initial, le type dynamique de l'objet sur lequel le pointeur de membre est déréférencé doit contenir le membre d'origine; voir 5.5 expr.mptr.oper.]

11) types de fonctions (y compris celles utilisées dans la fonction pointeur vers membre) types) ne sont jamais qualifiés pour le cv; voir 8.3.5 dcl.fct.

En bref, vous pouvez convertir à partir d'un dérivé D::* base B::* si vous pouvez convertir un B::*