Для функций, не являющихся членами, тип, такой как typedef void(Function)()
, имеет несколько применений, но для функций-членов единственным приложением является объявление переменной, которая содержит указатель на функцию. Следовательно, кроме стилистических предпочтений, нет строгой необходимости разрешать этот синтаксис, и он был исключен из стандарта.
Фон
::
является оператором разрешения области, а синтаксис X::Y
зарезервирован для static
доступа к элементу, если X
является типом класса. Таким образом, X::*Z
был изобретен другой синтаксис для определения указатель на член .
Забудьте на некоторое время функцию-член , просто подумайте о элемент-данные и посмотрите этот код:
struct X
{
int a;
};
int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;
Он определяет указатель на данные члена , и cout
использует его для печати значения a
объекта x
, и он печатает:
100
Демо: http://www.ideone.com/De2H1
Теперь подумайте, если бы X::pa
(в отличие от X::*pa
) было разрешено это сделать, то вы написали вышеприведенное как:
int X::pa = X::a; //not &X::a
Видя этот синтаксис, как бы вы узнали, является ли X::a
элементом static
или нестатическим? Это одна из причин, по которой Стандарт разработал синтаксис указатель на элемент и единообразно применяет его к нестатическим данным-элементам , а также нестатическим элементам -функции .
На самом деле, вы не можете написать X::a
, вы должны написать &X::a
. Синтаксис X::a
приведет к ошибке компиляции (см. this ).
Теперь расширьте этот аргумент member-data до member-function . Предположим, у вас есть typedef, определенный как:
typedef void fun();
тогда как вы думаете, что делает следующий код?
struct X
{
fun a;
};
Ну, он определяет член a
типа fun
(который является функцией без аргументов и возвращает void) и эквивалентен этому:
struct X
{
void a();
};
Удивлены? Продолжайте читать.
struct X
{
fun a; //equivalent to this: void a();
};
void X::a() //yes, you can do this!
{
cout << "haha" << endl;
}
Мы можем использовать точно такой же синтаксис для ссылки на a
, который теперь является функцией-членом:
X x;
x.a(); //normal function call
void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member
Сходство - синтаксис справа: &X::a
. Независимо от того, относится ли a
к функции-члену или данным-членам, синтаксис один и тот же.
Демо: http://www.ideone.com/Y80Mf
Вывод:
Поскольку мы знаем, что мы не можем записать X::a
в RHS, независимо от того, является ли a
данными-членами или функцией-членом. Единственным допустимым синтаксисом является &X::f
, который требует, чтобы целевым типом (на LHS) также был указатель , что, в свою очередь, делает синтаксис void (X::*pa)()
абсолютно необходимым и фундаментальным, так как соответствует другому синтаксису в языке.