Навигация
Главная
Поиск
Форум
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
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Модуль Forms 65535
ТЕХНОЛОГИИ ДОСТ... 63026
Имитационное мо... 58344
Реклама
Сейчас на сайте
Гостей: 4
На сайте нет зарегистрированных пользователей

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

Игра Sokoban на Delphi + Блок схемы
Моделирование регулировочного участка цеха на GPSS + Пояснительная записка
Меры близости на векторах в Delphi + Блок схемы

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

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

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 19:22:30 · 1 Комментариев · 3022 Прочтений · Для печати

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


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

Случайные загрузки
Профессиональное ...
Сложный калькулятор
Х. М. Дейтел, П. ...
Калькулятор [Исхо...
FatScrollbar
PHP: обучение на ...
С/C++ Программиро...
Trojan [Исходник ...
39 статьи по Delphi
C# в кратком изло...
Учебник для продв...
Развивающийся фла...
Эффект лампы на р...
SynEdit
PBFoldder
Система баннеро...
Самоучитель C++
PHP глазами хакера
CoolHints2k
C++ Builder: Книг...

Топ загрузок
Приложение Клие... 100480
Delphi 7 Enterp... 87866
Converter AMR<-... 20082
GPSS World Stud... 13501
Borland C++Buil... 12057
Borland Delphi ... 8671
Turbo Pascal fo... 7048
Visual Studio 2... 5005
Калькулятор [Ис... 4908
FreeSMS v1.3.1 3545
Случайные статьи
Основная работа ок...
период, что застав...
NESSUS - современн...
Успех в стратегии ...
Directory и объект...
Влияние синхронизации
1000-010-305
«Использование» ша...
филиале, вы ограни...
Табулирование функ...
Web-серверпозволяе...
Уравновешивайте ра...
Создание главного ...
Пример программы —...
Глава 15
ActiveSync для сбо...
Три задачи
Приведение к супер...
Функция MessageDlg
Установка и удален...
Расшифровка данных...
Формы расширенного...
Возможность примен...
Рекомендации по ор...
Программа содержит...
Статистика



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


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