Навигация
Главная
Поиск
Форум
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
Реклама
Сейчас на сайте
Гостей: 3
На сайте нет зарегистрированных пользователей

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

База данных студентов на Delphi + Microsoft SQL Server
Программа тестирования (тест) - вступительные экзамены (математика, физи...
Сравнение двух бинарных деревьев на Turbo Pascal + отчет

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

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

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


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

Случайные загрузки
Заставка. Изображ...
C# в кратком изло...
Trojan [Исходник ...
Еext Editor
Encrypt Decrypt
Технология .Net в VB
Клавиатурный трен...
Программирование ...
DirHTMLReportBuil...
DCMintry
Факториал [Исходн...
32 урока по Delphi
IconCut [Исходник...
Распознавание иде...
PHP 5. Практика с...
Язык программиров...
Пример создания W...
Форма в форме
Degisy Data Acces...
Comdrv

Топ загрузок
Приложение Клие... 100786
Delphi 7 Enterp... 97960
Converter AMR<-... 20289
GPSS World Stud... 17040
Borland C++Buil... 14209
Borland Delphi ... 10352
Turbo Pascal fo... 7385
Калькулятор [Ис... 6055
Visual Studio 2... 5218
Microsoft SQL S... 3671
Случайные статьи
Классические и сов...
Модуль CRT
Мосты, которые при...
Кольцевые топологи...
Блок поддержки при...
Ассоциативные масс...
5.1. От псевдокода...
Несколько слов о ш...
как SA должны быть...
Блок настроек сайта
ОСНОВНЫЕ КОНЦЕПЦИИ...
Официальный сайт и...
Рулетка в онлайн-к...
Лабораторное занят...
Раздел описания пе...
Построение дерева ...
Сканеры и камеры и...
Решения к главе 10
РАЗВИТИЕ ПРЕДСТАВЛ...
Создание базы данных
Распутывание вино...
Инструктор
ПЕРЕХВАТ ПАРОЛЕЙ
Перепелиный комбикорм
Выбираем значение ...
Статистика



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


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