Указатели на функции — различия между версиями

Материал из SEWiki
Перейти к: навигация, поиск
(Указатели на функции в С++)
 
(не показаны 4 промежуточные версии 3 участников)
Строка 2: Строка 2:
 
Рассмотрим метод qsort, который имеет прототип:
 
Рассмотрим метод qsort, который имеет прототип:
 
<source lang="cpp">
 
<source lang="cpp">
void qsort(void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *));
+
void qsort(void *base, size_t nmemb, size_t size,  
 +
          int (*compare)(const void *, const void *));
 
</source>
 
</source>
 
где  
 
где  
Строка 8: Строка 9:
 
int (*compare)(const void *a, const void *b)
 
int (*compare)(const void *a, const void *b)
 
</source>
 
</source>
указатель на функцию, которая имеет 2 параметра, и должна возращать значение:
+
указатель на функцию, которая имеет 2 параметра, и возращает значение:
 
* > 0, если a > b  
 
* > 0, если a > b  
 
* = 0, если a == b
 
* = 0, если a == b
Строка 19: Строка 20:
 
}
 
}
 
</source>
 
</source>
 +
Создадим объект структуры Person.
 
<source lang="cpp">
 
<source lang="cpp">
 
Person *m;
 
Person *m;
Строка 24: Строка 26:
 
</source>
 
</source>
  
Запишем функцию byage:
+
Определим функцию byage:
 
<source lang="cpp">
 
<source lang="cpp">
 
int byage(void const *p1, void const *p2) {
 
int byage(void const *p1, void const *p2) {
Строка 33: Строка 35:
 
Замечание:
 
Замечание:
  
В данном примере, что нет проверки типов.
+
В С нет проверки типов.
  
 
Замечание:
 
Замечание:
* При объявлении можем не писать параметры
+
* При объявлении указателя на функцию можем не писать параметры, то есть
 
+
<source lang="cpp">
 
int(*)(void const *, void const *);
 
int(*)(void const *, void const *);
 +
</source>
 
* Можно присвоить указателю на функцию значение 0
 
* Можно присвоить указателю на функцию значение 0
 
+
<source lang="cpp">
void а(void *, size_t , size_t , int (*)(const void *, const void *)) = 0;
+
void (*f)(void *, size_t , size_t , int (*)(const void *, const void *)) = 0;
 +
</source>
 +
При этом для таких конструкций можно использовать typedef <...>, где второе имя не будет указано, так как в его роли выступит f в левой части выражения.
 
* Присваивание
 
* Присваивание
 
+
<source lang="cpp">
 
f = &qsort;
 
f = &qsort;
 
+
</source>
Вызов
+
* Вызов
 
+
<source lang="cpp">
 
f(m, count, sizeof(Person), &byage);
 
f(m, count, sizeof(Person), &byage);
 +
</source>
  
 
== Указатели на функции в С++ ==
 
== Указатели на функции в С++ ==
  
Одно из отличие С и С++ - в С++ есть перегрузка. Тогда получается
+
Одно из отличий С и С++ - в С++ есть перегрузка. Тогда получается
 
<source lang="cpp">
 
<source lang="cpp">
F f = qsort; // будет вызываться, что подойдет лучше всего
+
F f = qsort; // должна вызываться та, что подойдет лучше всего
 
</source>
 
</source>
 
Вопрос:
 
Вопрос:
Строка 62: Строка 68:
 
Ответ:
 
Ответ:
  
Рассмотрим пример 1:
+
Рассмотрим два примера.
 +
 
 +
Пример 1:
 +
 
 
<source lang="cpp">
 
<source lang="cpp">
 
template <class It, class F> void A(It p, It q, F f);
 
template <class It, class F> void A(It p, It q, F f);
Строка 68: Строка 77:
 
</source>
 
</source>
  
пример 2:
+
Пример 2:
 
<source lang="cpp">
 
<source lang="cpp">
 
template <class T> T sqrt(T *);
 
template <class T> T sqrt(T *);
Строка 114: Строка 123:
 
Вопрос:
 
Вопрос:
  
Мы имеем указатель на мембер класса. Можем ли мы его передавать как параметр функции?
+
Мы имеем указатель на член класса. Можем ли мы его передавать как параметр функции?
  
 
Ответ:
 
Ответ:
  
Да, можем. К примеру,
+
Да, можем. Пример,
  
 
<source lang="cpp">
 
<source lang="cpp">
Строка 127: Строка 136:
  
 
Замечание:
 
Замечание:
Указатели на мемберы не приводяться ник чему. Они могут проверяться на равенство 0.
+
Указатели на члены класса не приводяться ни к чему. Они могут проверяться на равенство 0.

Текущая версия на 02:35, 11 июня 2012

Указатели на функции в С

Рассмотрим метод qsort, который имеет прототип:

void qsort(void *base, size_t nmemb, size_t size, 
           int (*compare)(const void *, const void *));

где

int (*compare)(const void *a, const void *b)

указатель на функцию, которая имеет 2 параметра, и возращает значение:

  • > 0, если a > b
  • = 0, если a == b
  • < 0, если a < b

Рассмотрим пример:

struct Person {
	int m_age;
}

Создадим объект структуры Person.

Person *m;
qsort(m, count, sizeof(Person), &(byage));

Определим функцию byage:

int byage(void const *p1, void const *p2) {
	return ((Person *)p1)->age - ((Person *)p2)->age;
}

Замечание:

В С нет проверки типов.

Замечание:

  • При объявлении указателя на функцию можем не писать параметры, то есть
int(*)(void const *, void const *);
  • Можно присвоить указателю на функцию значение 0
void (*f)(void *, size_t , size_t , int (*)(const void *, const void *)) = 0;

При этом для таких конструкций можно использовать typedef <...>, где второе имя не будет указано, так как в его роли выступит f в левой части выражения.

  • Присваивание
f = &qsort;
  • Вызов
f(m, count, sizeof(Person), &byage);

Указатели на функции в С++

Одно из отличий С и С++ - в С++ есть перегрузка. Тогда получается

F f = qsort; // должна вызываться та, что подойдет лучше всего

Вопрос:

Как происходит работа с шаблонными функциями?

Ответ:

Рассмотрим два примера.

Пример 1:

template <class It, class F> void A(It p, It q, F f);
A(v.begin(), v.end(), (int(*)(int))sqrt); // необходимо приведение типов

Пример 2:

template <class T> T sqrt(T *);

Нам необходимо проинстанциировать функцию, для этого существует несколько способов:

  • sqrt(0);
    
  • template sqrt<int>; // явно для T = int
    

В результате, метод A мы можем вызывать:

A(v.begin(), v.end(), sqrt<int>);

Вопрос: Как получить указатели на члены класса? Ответ: Рассмотрим пример:

struct Person {
	int m_age;
	int m_salary;
	string m_name;
	string name() {
		return m_name;	
	}
}

Тогда

int Person::(*p) = &Person::m_age;
string (Person::*f)() const = &Person::name;

Далее имеем

Person pers;
(pers.*p) = 10;
(pers.*f)();

Вопрос:

Мы имеем указатель на член класса. Можем ли мы его передавать как параметр функции?

Ответ:

Да, можем. Пример,

struct by_field {
	by_field(int Person::*field)
}

Замечание: Указатели на члены класса не приводяться ни к чему. Они могут проверяться на равенство 0.