Навигация
Главная
Поиск
Форум
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,372
новичок: vausoz
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

База данных - рабочее место кассира на Delphi + бд Access
Метод половинного деления для нахождения корня уровнения на Turbo Pascal...
Моделирование интернет магазина (Apache, Php, Html) на GPSS + Блок схема

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

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 Комментариев · 5217 Прочтений · Для печати

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


Комментарии
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...
Шаблон для новост...

Случайные загрузки
Просмотр файлов и...
Шейдеры в Delphi
Система баннеро...
Программирование ...
SMLPack v1.0
Converter AMR<->W...
PrevInst
Простой пример ка...
Globus VCL Extent...
THttpScan v4.1
32 урока по Delphi
Применение фильтр...
TsHintManager
Ehlib
Популярные загрузки
Динамические за...
БД студентов
SODA [Исходник на...
Exe in exe
Counter [Исходник...

Топ загрузок
Приложение Клие... 100793
Delphi 7 Enterp... 98016
Converter AMR<-... 20298
GPSS World Stud... 17059
Borland C++Buil... 14239
Borland Delphi ... 10374
Turbo Pascal fo... 7390
Калькулятор [Ис... 6080
Visual Studio 2... 5228
Microsoft SQL S... 3674
Случайные статьи
Инвариант на второ...
Режимы экспозиции ...
Планирование разве...
Как заработать в к...
4.1. Порождение ...
Введение
Базовые криптограф...
Обработка исключит...
Определение процес...
Перегрузка операций
Планирование глоба...
Синхронизация буфе...
Функция InstallUse...
Управление контентом
Шаблоны и модули
Табл. 13-14.
Реализация функции...
Лиопетри на Кипре
Вход в SQL*PLUS. ...
Свадебный фотограф
Вычислить произвед...
Изменение размера ...
Конструктор копии
Синтаксис - Микро ...
Инструмент исследо...
Статистика



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


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