C++03 std, §4.11 2 Pointeur sur membre des conversions:
Une rvalue de type "pointeur sur membre B de type cv T", où B est un type de classe, peuvent être convertis en une rvalue de type "pointeur sur membre des D de type cv T, où D est une classe dérivée (clause 10) de B. Si B est un inaccessible (clause 11), ambigu (10.2) ou virtuel (10.1) de la classe de base de D, un programme qui nécessite cette conversion est mal formé. Le résultat de la conversion désigne le même membre que le pointeur de membre avant la conversion a eu lieu, mais il se réfère à la classe de base militaire, comme s'il s'agissait d'un membre de la classe dérivée. Le résultat se rapporte au membre D instance de B. Puisque le résultat est de type "pointeur sur membre des 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 ont été déréférencés avec le B de sous-objet de D. Le membre null la valeur du pointeur est converti à l'null membre de la valeur du pointeur du type de destination. 52)
52)La règle de conversion de pointeurs sur des membres (à partir du pointeur de membre de base de pointeur de membre de la dérivée) apparaît inversé par rapport à la règle des pointeurs vers les objets (à partir de pointeur de dérivés de pointeur de base) (4.10, article 10). Cette inversion est nécessaire pour assurer la sécurité de type. Note qu'un pointeur de membre n'est pas un pointeur vers un objet ou un pointeur de fonction et les règles pour les conversions de ces pointeurs ne s'appliquent pas à des pointeurs vers les membres. En particulier, un pointeur de membre ne peut être converti à un void*.
En bref, vous pouvez convertir un pointeur sur un membre de l'accessibilité, de non-virtuel de la classe de base à un pointeur sur un membre d'une classe dérivée tant 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
...
La Conversion dans l'autre sens (par static_cast
) est régie par les § 5.2.9 9:
Une rvalue de type "pointeur sur membre des D de type cv1 T" peut être convertie en une valeur r de type "pointeur sur membre B de type cv2 T", où B est une classe de base (article 10 de la 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 membre null la valeur du pointeur (4.11 conv.mem) est converti à l'null membre de la valeur du pointeur 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. [Remarque: bien que la classe B n'a pas besoin de contenir de l'origine, 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) des types de Fonction (y compris ceux utilisés dans le pointeur de fonction membre
les types) ne sont jamais de cv qualifiés; voir 8.3.5 dcl.fct.
En bref, vous pouvez convertir à partir d'un dérivé D::*
de base - B::*
si vous pouvez convertir un B::*
d'un D::*
, bien que vous ne pouvez utiliser l' B::*
sur des objets de type D ou sont les descendants de D.