Почему для принятия значения указателя функции члена требуется классное определение класса даже изнутри класса?
При возврате указателя функции-члена в класс внутри одной из этих функций-членов класса мне все равно нужно указать класс. Я не могу просто взять адрес. Например, этот код отлично работает:
class Foo {
public:
void func(int param) { cout << param << endl; }
void (Foo::*getPointer())(int) { return &Foo::func; }
};
Но если в getPointer
я пытаюсь просто сделать: return &func
Я получаю эту ошибку:
prog.cpp: В функции-члена 'void (Foo::* Foo::getPointer())(int)
':
prog.cpp: 8: 43: error: ISO С++ запрещает принимать адрес неквалифицированной или нестационарной функции-члена в виде скобки, чтобы сформировать указатель на функцию-член. Скажите '&Foo::func
' [-fpermissive]
void (Foo::*getPointer())(int) { return &func; }
Почему я должен указывать класс, когда тот контекст, в котором я находится?
Ответы
Ответ 1
Указатели и указатели на элементы - это разные типы, мы можем видеть, что из раздела проект стандартного раздела С++ 3.9.2
[basic.compound], который включает составной тип для указателя, а также указатель на нестатический член класса и примечания
Статические члены класса - это объекты или функции, а указатели на них обычные указатели на объекты или функции
Эта проблема с этим, я думаю, хорошо описана в этой цитате в ответе от Johannes из Аннотированное справочное руководство по С++ (ARM):
Обратите внимание, что адрес-оператор должен быть явно использован для получения указатель на член; нет никакого неявного преобразования... Если бы было, мы будем иметь двусмысленность в контексте функции-члена... Для Например,
void B::f() {
int B::* p = &B::i; // ok
p = B::i; // error: B::i is an int
p = &i; // error: '&i'means '&this->i'
// which is an 'int*'
int *q = &i; // ok
q = B::i; // error: 'B::i is an int
q = &B::i; // error: '&B::i' is an 'int B::*'
}
В частности, эти строки:
int B::* p = &B::i; // OK
и
p = &i; // error: '&i'means '&this->i' which is an 'int*'
продемонстрируйте разницу между квалифицированным и неквалифицированным именем.
Ответ 2
(... был неправильный ответ...)
Это выглядит более странно в следующем контексте:
class Foo {
public:
virtual void func(int param) { cout << param << endl; }
void call(int x) { Foo::func(x); }
void (Foo::*getPointer())(int) { return &Foo::func; }
};
class Bar : public Foo {
public:
void func(int param) override { cout << "Hello world!" << endl; }
};
int main() {
Foo *a = new Bar();
auto p = a->getPointer();
(a->*p)(4);
a->call(4);
return 0;
}
Выходной сигнал
Привет мир
4
Вызов Foo::func
- это вызов func
в классе Foo
, а вызов &Foo::func
- это виртуальный вызов.