Прежде всего, рассмотрим объявление класса XXX.
class XXX { public: long x1; int x2; /*Данные-члены класса.*/ long getVal1() {return x1;} long getVal2() {return x2*x1;} /*Функции-члены класса без параметров.*/ int getVal3(int param) {return x2*param;} char* getVal4(char *str) {return str;} /*Функции-члены класса с параметрами.*/ static int f1() {return 100;} static int f2() {return 10;} static int f3(int param) {return param;} /* Определение различных статических функций*/ XXX(long val1, int val2){x1 = val1; x2 = val2;} /*Конструктор.*/ };
Поскольку нестатические функции-члены формально, а нестатические данные-члены фактически не существуют без объекта-представителя класса, определение указателя на компонент класса (член класса или функцию-член) отличается от определения указателя на объект или обычную функцию.
Для объявления указателя на нестатическую функцию используется специальная синтаксическая конструкция, состоящая из спецификатора объявления и заключённого в скобки квалифицированного имени указателя, состоящего из имени класса, операции доступа к члену класса ::, разделителя * , собственно имени указателя, закрывающей скобки и списка параметров:
int (XXX::*fp_3) (int);
Подобный указатель может быть проинициализирован инициализатором, состоящим из операции присвоения, операции взятия адреса и квалифицированного имени соответствующей функции-члена:
int (XXX::*fp_3) (int) = &XXX::getVal1;
Вот и нашлась достойная область применения квалифицированным именам.
Как известно, значение унарного выражения, состоящего из операции взятия и операнда, который является именем функции и первичного выражения, состоящего из имени функции эквивалентны. Это адрес данной функции. Поэтому поэтому в качестве инициализирующего выражения для указателя на функцию-член класса также может быть использовано первичное выражение, представляющее собой квалифицированное имя функции-члена:
Fp_3 = XXX::getVal2
Класс - это не объект! И не совсем понятно, какое значение имеет адрес нестатичесного члена класса. Значение проинициализированного указателя на нестатическую компоненту остаётся неопределённым.
Оно определяется лишь в результате выполнения операций обращения к членам класса .* и ->* .
При этом функция-член класса вызывается по указателю на компоненту относительно конкретного объекта или указателя на объект-представитель класса. Первым операндом операций обращения к членам класса является l-выражение, ссылающееся на объект (возможно, что имя объекта) или указатель на объект, вторым операндом является ссылка на указатель на компоненту класса:
int val = (q.*fp)(6); char val = (pq->*fp4)("new string");
Аналогичным образом осуществляется объявление и инициализация указателей на данные-члены класса. При этом структура объявления указателя на член класса проще (нет спецификации возвращаемого значения, не нужно указывать список параметров). Это не функция, здесь дело обходится спецификацией объявления и квалифицированными именами указателей:
long (XXX::*px1) = &XXX::x1; // Определение и инициализация указателя на член класса XXX типа long q.*px11 = 10; // p - объект-представитель класса XXX. pq->*px11 = 10; // pq - указатель на объект-представитель класса XXX.
Основные приёмы работы с указателями на функции-члены демонстрируются на следующих примерах:
class XXX { public: long x1; int x2; /*Данные-члены класса.*/ long getVal1() {return x1;} long getVal2() {return x2*x1;} /*Функции-члены класса без параметров.*/ int getVal3(int param) {return x2*param;} char* getVal4(char *str) {return str;} /*Функции-члены класса с параметрами.*/ static int f1() {return 100;} static int f2() {return 10;} static int f3(int param) {return param;} /* Определение различных статических функций*/ XXX(long val1, int val2){x1 = val1; x2 = val2;} /*Конструктор.*/ }; void main() { XXX q(1,2);/* Определение объекта.*/ XXX* pq = new (XXX); pq->x1 = 100; pq->x2 = 100; /*Определение и инициализация объекта по указателю.*/ long (XXX::*fp_0) (); /*Указатель на функцию-член класса.*/ long (XXX::*fp_1) () = &XXX::getVal1; /* Проинициализированный указатель на функцию-член класса. Его значение является относительной величиной и равняется значению смещения функции-члена относительно первого члена класса. */ fp_0 = XXX::getVal1; /* Инициализация первого указателя. Один и тот же указатель можно настраивать на различные функции-члены класса. Главное, чтобы у всех этих функций-членов совпадали списки параметров и возвращаемые значения функций. */ long val_1 = (q.*fp1)(); /*Вызов функции-члена класса по указателю из объекта.*/ long val_2 = (pq->*fp0)(); /* Вызов функции-члена класса по указателю с помощью указателя на объект. */ int (XXX::*fp_3) (int) = &XXX::getVal3; /* Проинициализированный указатель на функцию-член класса. С параметрами типа int. */ int val_3 = (q.*fp_3)(6); /* Вызов функции-члена класса по указателю из объекта с передачей параметров. */ char* (XXX::*fp_4) (char) = &XXX::getVal3; /* Проинициализированный указатель на функцию-член класса с параметрами типа int. */ char val_4 = (pq->*fp4)("new string"); /* Вызов функции-члена класса по указателю с помощью указателя на объект. */ int (*fp_5) () = &XXX::f1; /* Указатель на статическую функцию объявляется без спецификации класса. Явная спецификация класса необходима лишь при инициализации указателя. */ int retval = (*fp_5)(); /*Вызов статической функции по указателю.*/ fp_5 = XXX::f2; /* Перенастройка статического указателя. Главное требование - совпадение списков параметров и типа возвращаемого значения. */ int (*fp_6) (int) = &XXX::f3; /*Указатель на статическую функцию с параметрами.*/ int retval = (*fp_6)(255); /*Вызов статической функции с параметрами по указателю.*/ long (XXX::*px1) = &XXX::x1; /*Определили и проинициализировали указатель на член класса long*/ q.*px11 = 10; /*Используя указатель на компоненту класса, изменили значение переменной x1 объекта q, представляющего класс XXX. */ pq->*px11 = 10; /*Используя указатель на компоненту класса, изменили значение переменной x1 объекта, представляющего класс XXX и расположенного по адресу pq. */ }
Вызов статических функций-членов класса не требует никаких объектов и указателей на объекты. От обычных функций их отличает лишь специфическая область видимости.
Назад | Содержание | Вперед