Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / C / C++ / Введение в язык C++ / Функции и Файлы /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Функции - Программирование от RIN.RU
Функции



Указатель на Функцию


С функцией можно делать только две вещи: вызывать ее и брать ее адрес. Указатель, полученный взятием адреса функции, можно затем использовать для вызова этой функции.


Например:


void error(char* p) { /* ... */ }




void (*efct)(char*); // указатель на функцию




void f()
{
efct = &error; // efct указывает на error
(*efct)("error"); // вызов error через efct
}


Чтобы вызвать функцию через указатель, например, efct, надо сначала этот указатель разыменовать, *efct. Поскольку операция вызова функции () имеет более высокий приоритет, чем операция разыменования *, то нельзя писать просто *efct("error"). Это означает *efct("error"), а это ошибка в типе. То же относится и к синтаксису описаний (см. также этот пункт).


Заметьте, что у указателей на функции типы параметров описываются точно также, как и в самих функциях. В присваиваниях указателя должно соблюдаться точное соответствие полного типа функции.


Например:


void (*pf)(char*); // указатель на void(char*)
void f1(char*); // void(char*)
int f2(char*); // int(char*)
void f3(int*); // void(int*)




void f()
{
pf = &f1; // ok
pf = &f2; // ошибка: не подходит возвращаемый тип
pf = &f3; // ошибка: не подходит тип параметра




(*pf)("asdf"); // ok
(*pf)(1); // ошибка: не подходит тип параметра




int i = (*pf)("qwer"); // ошибка: void присваивается int"у
}


Правила передачи параметров для непосредственных вызовов функции и для вызовов функции через указатель одни и те же.


Часто, чтобы избежать использования какого-либо неочевидного синтаксиса, бывает удобно определить имя типа указатель-на-функцию.


Например:


typedef int (*SIG_TYP)(); // из
typedef void (*SIG_ARG_TYP);
SIG_TYP signal(int,SIG_ARG_TYP);


Бывает часто полезен вектор указателей на функцию. Например, система меню для моего редактора с мышью*4 реализована с помощью векторов указателей на функции для представления действий. Подробно эту систему здесь описать не получится, но вот общая идея:


typedef void (*PF)();




PF edit_ops[] = { // операции редактирования
cut, paste, snarf, search
};




PF file_ops[] = { // управление файлом
open, reshape, close, write
};


Затем определяем и инициализируем указатели, определяющие действия, выбранные в меню, которое связано с кнопками (button) мыши:


PF* button2 = edit_ops;
PF* button3 = file_ops;


В полной реализации для определения каждого пункта меню требуется больше информации. Например, где-то должна храниться строка, задающая текст, который высвечивается. При использовании системы значение кнопок мыши часто меняется в зависимости от ситуации. Эти изменения осуществляются (частично) посредством смены значений указателей кнопок. Когда пользователь выбирает пункт меню, например пункт 3 для кнопки 2, выполняется связанное с ним действие:


(button2[3])();


Один из способов оценить огромную мощь указателей на функции - это попробовать написать такую систему не используя их. Меню можно менять в ходе использования программы, внося новые функции в таблицу действий. Во время выполнения можно также легко сконструировать новое меню.


Указатели на функции можно использовать для задания полиморфных подпрограмм, то есть подпрограмм, которые могут применяться к объектам многих различных типов:


typedef int (*CFT)(char*,char*);




int sort(char* base, unsigned n, int sz, CFT cmp)
/*
Сортирует "n" элементов вектора "base"
в возрастающем порядке
с помощью функции сравнения, указываемой "cmp".
Размер элементов "sz".


Очень неэффективный алгоритм: пузырьковая сортировка
*/
{
for (int i=0; iname, Puser(q)->name);
}


int cmp2(char*p, char* q) // Сравнивает числа dept
{
return Puser(p)->dept-Puser(q)->dept;
}


Эта программа сортирует и печатает:


main ()
{
sort((char*)heads,6,sizeof(user),cmp1);
print_id(heads,6); // в алфавитном порядке
cout << "\n";
sort((char*)heads,6,sizeof(user),cmp2);
print_id(heads,6); // по порядку подразделений
}


Можно взять адрес inline-функции, как, впрочем, и адрес перегруженной функции.

<<<  Назад
 1  2  3  4  5 


 8  Комментарии к статье  8 8  Обсудить в чате

8  В тему

Введение

Компоновка

Заголовочные Файлы

Файлы как Модули

Как Создать Библиотеку

Макросы

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь