Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию
    главная     хостинг    
Поиск по сайту:  
Смотрите также
Языки программирования
C#
MS Visual C++
Borland C++
C++ Builder
Visual Basic
Quick Basic
Turbo Pascal
Delphi
JavaScript
Java
PHP
Perl
Assembler
AutoLisp
Fortran
Python
1C

Интернет-технологии
HTML
VRML
HTTP
CGI
FTP
Proxy
DNS
протоколы TCP/IP
Apache

Web-дизайн
HTML
Дизайн
VRML
PhotoShop
Cookie
CGI
SSI
CSS
ASP
PHP
Perl

Программирование игр
DirectDraw
DirectSound
Direct3D
OpenGL
3D-графика
Графика под DOS

Алгоритмы
Численные методы
Обработка данных

Сис. программирование
Драйверы

Базы данных
MySQL
SQL

Другое

Хостинг


Друзья
demaker.ru
Реклама

Лучший хостинг. Аренда серверов




helloworld.ru

Указатели на компоненты класса. Доступ по указателю

Прежде всего, рассмотрим объявление класса 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. */
}

Вызов статических функций-членов класса не требует никаких объектов и указателей на объекты. От обычных функций их отличает лишь специфическая область видимости.


[ Назад | Оглавление | Далее ]









helloworld.ru © 2001-2021
Все права защищены