C ++ 03 std, §4.11 2 Указатель на преобразование членов:
Rvalue типа «указатель на член B типа cv T», где B - тип класса, может быть преобразовано в rvalue типа «указатель на член D типа cv. T », где D - производный класс (пункт 10) от B. Если B - недоступный (пункт 11), неоднозначный (10.2) или виртуальный (10.1) базовый класс D, программа, которая требует этого преобразования плохо сформирован. Результат преобразования относится к тому же члену, что и указатель на член до того, как произошло преобразование, но он относится к члену базового класса, как если бы он был членом производного класса. Результат относится к члену в экземпляре D из B. Поскольку результат имеет тип «указатель на член D типа cv T», его можно разыменовать с помощью объекта D. Результат такой же, как если бы указатель на член B был разыменован с подобъектом B объекта D. Значение указателя на нулевой член преобразуется в значение указателя на нулевой член целевого типа. 52)
52) Правило преобразования указателей в члены (от указателя к члену базы в указатель на член производного) кажется инвертированным по сравнению с правилом для указателей на объекты (от указателя к производному к указателю на основание). ) (4.10, п.10). Эта инверсия необходима для обеспечения безопасности типа. Обратите внимание, что указатель на член не является указателем на объект или указателем на функцию, и правила преобразования таких указателей не применяются к указателям на члены. В частности, указатель на член не может быть преобразован в void *.
Короче говоря, вы можете преобразовать указатель на член доступного невиртуального базового класса в указатель на член производного класса, если этот член не является неоднозначным.
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
...
Преобразование в другом направлении (через static_cast
) регулируется § 5.2.9 9:
Rvalue типа "указатель на член D типа cv1 T" может быть преобразован в rvalue типа "указатель на член B типа cv2 T", где B - базовый класс (пункт 10 класс. производный) от D, если существует допустимое стандартное преобразование из "указателя на член B типа T" в "указатель на член D типа T" (4.11 conv.mem ( 4,11 конв. mem) преобразуется в значение указателя на нулевой член целевого типа. Если класс B содержит исходный член или является базовым или производным классом класса, содержащего исходный член, результирующий указатель на член указывает на исходный член. В противном случае результат приведения не определен. [Примечание: хотя класс B не обязательно должен содержать исходный член, динамический тип объекта, на котором разыменовывается указатель на член, должен содержать исходный член; см. 5.5 expr.mptr.oper.]
11) Типы функций (включая те, которые используются в указателях на типы функций-членов) никогда не квалифицируются cv; см. 8.3. 5 dcl.fct.
Короче говоря, вы можете преобразовать производный D::*
в базовый B::*
, если вы можете преобразовать из B::*
в D::*
, хотя вы можете использовать B::*
только для объектов, которые относятся к типу D или являются производными от D.
person
outis
schedule
22.04.2010