Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 10
На сайте нет зарегистрированных пользователей

Пользователей: 13,370
новичок: dogoco6
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

База данных междугородних телефонных разговоров на Delphi
Моделирование вычислительного центра на GPSS + Отчет + Блок схема
Обратное размещение элементов ЭВС на Delphi + Пояснительная записка

Вызов функции через указатель
Вызов функции через указатель выполняется так: (*имя-указателя)(аргументы);
Тот же вызов можно написать в более простой форме: имя-указателя(аргументы);
Рассмотрим несколько простых примеров. Допустим, у нас объявлен указатель на функцию:

int (*pf)(void);



Этому указателю можно присвоить адрес любой функции с таким же прототипом, в том числе и библиотечной. Например, такой прототип имеет функция-генератор случайного числа rand (), который объявлен в заголовке библиотеки <cstdlib>:
int fl(void) { return 1; }
// вызов fl() // вызов f2() // вызов rand()
int f2(void) { return 2; }
pf = fl; cout << pf() << endl;
pf = f2; cout << pf() << endl;
pf = &rand; cout << pf() << endl;



Напишем теперь простой класс
class Constant { int value; public:
Constant(const int &a): value(a) {} int get(void) { return value; }
};



Метод get () с виду имеет тот же прототип, что и функции в приведенном ранее фрагменте. Однако попытки присвоить адрес метода get() указателю pf компилятор пресекает «на корню». Да и не совсем понятно, как этот адрес задавать. Вариантов два.
1. Объявить объект и взять адрес метода в объекте:
Constant А(5); pf = &A.get();



2. Не объявлять объект, а приписать префикс класса:
pf = &Constant::get;
Первый вариант вообще неверный: и Visual C++.NET 2003, и Borland С++ Builder 6 сообщают, что операцию взятия адреса & так использовать нельзя. Второй вариант ближе к истине: оба компилятора сообщают только о невозможности выполнить преобразование типов. Попытки прописать преобразование явно не проходят:
pf = static_cast<int (*)(void)>(&Constant::get);
pf = reinterpret_cast<int (*)(void)>(&Constant::get);
pf = (int (*)(void))(&Constant::get);



Все эти варианты вызывают ту же ошибку компиляции — невозможность преобразования типов. Таким образом, тип указателя на метод класса кардинально отличается от типа указателя на функцию: адрес метода нельзя присвоить указателю на функцию, даже если внешне их прототипы совпадают. Это становится понятным, если мы вспомним, что нестатические методы получают дополнительный параметр — указатель thi s.
Аналогично, нельзя присвоить обычному указателю на функцию адрес виртуального метода — в этом случае дело усугубляется еще наличием в составе объекта указателя на таблицу виртуальных методов. А вот to статическими методами картина другая! Статический метод не получает никаких «лишних параметров», поэтому его адрес можно присваивать обычному указателю на функцию без всяких преобразований. Добавим в класс Constant статическое поле и статический метод с нужным нам прототипом:
class Constant { int value;
static int d; public:
Constant(const int &a): value(a) {} int get(void) { return value; }
static int getd(void) { return d; } // статический метод
};



Тогда нашему указателю pf можно присвоить адрес статического метода согласно второму из приведенных ранее вариантов, например:
pf = Constant:rgetd; // или pf = &Constant::getd;



Префикс, естественно, необходимо писать.
Указатель на метод объявляется по-другому (см. п. п. 8.3.3 в [1]) — нужно задать имя класса в качестве префикса:
int (Constant::*pm)(void);



Такому указателю можно присваивать адреса обычных и виртуальных методов согласно второму из приведенных ранее вариантов, например:
pm = &Constant::get; // или рт = Constant::get;
Адрес статического метода, так же как и адрес обычной функции, такому указателю присвоить нельзя — возникает ошибка трансляции: компилятор сообщает о невозможности выполнить преобразование типов.
И косвенный вызов метода выполняется по-другому — с помощью операции выбора члена класса . * или ->* (см. п. 5.5 в [1]). Несмотря на то что указатель на член класса является отдельной независимой от класса переменной, вызов метода по указателю возможен только при наличии объекта, например:
Constant А(5);
cout << (A.*pm)() << endl;



Выражение (A. *pm) () означает следующее: для объекта А вызвать метод, чей адрес записан в указателе рт. Слева от операции . * — объект, справа — указатель на метод. Скобки вокруг выражения А. *рт писать обязательно, так как приоритет операции вызова функции (()) выше, чем приоритет операции выбора члена класса (. *).
В выражении (объект. *указатель) можно заменить часть объект, записью указатель->, например:
Constant *рс = new Constant(7); cout << (pc->*pm)() << endl;



Обратите внимание: в выражении (pc->*pm) слева — обычный указатель на динамический объект, а справа — указатель на метод этого объекта. Это два совершенно разных типа указателя.
Интересно, что в Visual C++.NET 2003 размер sizeof (pf) указателя на функцию совпадает с размером si zeof (pm) указателя на член класса и равен 4 байтам. А вот система Borland С++ Builder 6 выдает совершенно разные цифры: размер указателя на функцию равен 4 байтам, а размер указателя на метод — 12 байт!
Опубликовал Kest December 31 2013 15:22:30 · 1 Комментариев · 4683 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Cyb3rS0nic January 15 2014 19:01:10
Спасибо за интересную, а главное - познавательную статью. С ++ начал обучать совсем недавно. На этом сайте нашел много полезных для меня вещей. Нравится, когда всё "коротко и ясно", и читать долго не нужно, что весьма радует. А то бывает, что-либо нужно найти из функции, а статья длиннючая, вот и приходится читать всю. В общем спасибо за статейку! smiley
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Battle.Net - мони...
index.php + мод ...
C++ Builder 6 СПР...
Microsoft Press -...
IpEditAdress
SearchAndReplace
RxLIB
Запрет гостям ск...
Искусство програм...
Шаблон для новост...
DelTrayIcon [Исхо...
CoolHints2k
Интерактивный инт...
AlnComponents
Proeffectimage
AntiRus
Самоучитель C++
IconCut [Исходник...
3d Tank [Исходник...
Длинный заголовок...

Топ загрузок
Приложение Клие... 100774
Delphi 7 Enterp... 97836
Converter AMR<-... 20268
GPSS World Stud... 17014
Borland C++Buil... 14191
Borland Delphi ... 10291
Turbo Pascal fo... 7374
Калькулятор [Ис... 5984
Visual Studio 2... 5207
Microsoft SQL S... 3661
Случайные статьи
Игры. Как победить...
contoso
3.1. Принципы
9. Инициализация в...
9.4. Принципы
Безызбыточное коди...
Объекты, свойства ...
2. С помощью IEAK ...
Случайное рехеширо...
Challenge Handshak...
Отображение в Dat...
Создание файла сод...
Впрочем, зачастую ...
Поиск и редактиров...
Когда использовать...
Процедура SetActiv...
STORAGE (ПАМЯТЬ)
Клиентские компьют...
Windows 2000
The profit of gamb...
Конфигурационный ф...
MissingMappingActi...
Операция индексиро...
Решения к главе 7
Играть онлайн в иг...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?