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

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



>>> ПОДРОБНЕЕ ЖМИТЕ ЗДЕСЬ <<<

































Указатель На Функцию Член
Date Пт 18 Июль 2014 Редакция Пн 12 Октябрь 2015 Категория comp Теги C / Cpp
Сначала рассмотрим указатели на обычные функции, а затем перейдем к функциям-членам класса.
Указатель на функцию -- это переменная, которая хранит адрес кода функции в памяти.
1. Функции как аргументы других функций
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));

необходимо передать указатель на функцию compar, задающую порядок сортировки (по возрастанию, по убыванию и т. п.).
или, если угодно, функции обратного вызова. Они вызываются как реакция программы на то или иное действие. Например, в коде графического интерфейса может встретится функция, создающая "кнопку"
void createButton(int x, int y, const char *text, function callback_func);

для чего нужно передать ей: координаты кнопки, текст надписи на ней, и функцию (тот самый callback), вызываемую при нажатии на кнопку.
Здесь func -- указатель на функцию, принимающую один аргумент (int) и возвращающую void.
Представьте, что вы объявляете функцию func, принимающую целочисленный аргумент и ничего не возвращающую:
Указатель на эту функцию обозначается как *func. Поскольку скобки имеют высший приоритет в сравнении со звездочкой, то запись
вместо ожидаемого, даст объявление функции, возвращающей указатель на void. Чтобы *func сработало раньше, нужно его также взять в скобки. В итоге получим:
Разобрать более сложные случаи поможет правило чтения по спирали.
Тем не менее, даже досконально разобравшись в синтаксисе указателей на функции, лучше использовать подобную запись как можно реже. Вместо этого рекомендуется использовать typedef:
Чтобы инициализировать указатель на функцию, ему нужно присвоить адрес реальной функции. Ниже, указателю присваивается значение адреса функции my_int_func:
#include

void my_int_func(int x)
{
printf("%d\n", x);
}

int main()
{
typedef void (*func)(int);
/* the ampersand is actually optional */
func = &my_int_func;

return 0;
}

Чтобы вызвать функцию my_int_func, на которую указывает указатель func, вы должны разыменовать этот указатель (*func) (помним про скобки, изменяющие приоритет операторов!). Это работает, но в действительности все проще: компилятор трактует вызов указателя как вызов функции, на которую тот указывает, а разыменование происходит автоматически:
#include
void my_int_func(int x)
{
printf("%d\n", x);
}


int main()
{
typedef void (*func)(int);
func = &my_int_func;

/* можно подробно */
(*func)(2);
/* но можно и проще */
func(2);

return 0;
}

Постепенно подходим к основной теме статьи. Предыдущие примеры работали как в С, так и в С++. Теперь мы переходим к использованию классов и, следовательно, С++.
В примере ниже вводится тип данных function и глобальная переменная этого типа. Методы класса A служат для выбора нужной функции и ее вызова. Заметьте, что речь все еще идет об отдельной функции, а не о члене класса.
#include

typedef void (*function)(void); // тип данных для функции

function switchFunc; // создадим переменную этого типа

// Функции, соответствующие типу function
void myFunc() { std::cout << "myFunc()" << std::endl; }
void yourFunc() { std::cout << "yourFunc()" << std::endl; }


class A
{
public:

void setFunc(function func);
void call();
};

// Устанавливает, какая функция будет вызываться
void A::setFunc(function func)
{
switchFunc = func;
}

// Вызывает выбранную функцию
void A::call()
{
std::cout << "Call ";
switchFunc();
}


int main()
{
A a;

a.setFunc(myFunc);
a.call();

a.setFunc(yourFunc);
a.call();
}

Как видно, использование указателей на функции в качестве аргументов методов класса ничего нового не привносит.
Метод класса, отличается от обычной функции, в частности, тем, что неявно содержит среди своих аргументов указатель на объект того класса, которому он принадлежит (this). В результате тип "указатель на функцию-член" должен отличаться от типа "указатель на функцию". Чем же?
Если это -- обычная функция или статический метод класса, то ее тип нам уже известен:
А если это нестатический метод класса (к примеру, класса A), то ее тип запишется так:
То есть, обращаться с указателями на статические методы можно также, как с указателями на обычные функции. Действительно, статический метод не связан с каким либо определенным объектом класса, не содержит среди своих аргументов указателя на конкретный объект, и по сути является обычной функцией, по каким-то соображениям добавленной в класс.
Далее мы будем рассматривать только нестатические методы, и использовать термины "функция-член класса" и "метод" как синонимы.
Изменим предыдущий пример, внося тип указатель-на-функцию и переменную этого типа внутрь класса:
#include

class A
{
typedef void (A::*function)(void);
function switchFunc;

public:

void setFunc(function func);
void call();

void myFunc();
void yourFunc();
};

void A::myFunc() { std::cout << "myFunc()" << std::endl; }
void A::yourFunc() { std::cout << "yourFunc()" << std::endl; }

void A::setFunc(function func)
{
switchFunc = func;
}

void A::call()
{
std::cout << "Call ";
(this->*switchFunc)();
}


int main()
{
A a;

a.setFunc(&A::myFunc);
a.call();

a.setFunc(&A::yourFunc);
a.call();
}

Бросается в глаза различие в вызове метода и функции
switchFunc(); // для функции
(this->*switchFunc)(); // для метода

Действительно, нестатический метод класса относится к конкретному экземпляру класса (объекту) и потому вызывается через this->, а так как switchFunc -- это указатель, то понадобилось его разыменование.
Обращает на себя внимание и вызов функции, соответствующей типу function
typedef void (A::*function)(void); // тип
&A::myFunc // вызов функции

Неожиданного здесь нет: раз мы задали такой тип -- указатель на функцию-член класса A -- то должны и вызывать функции этого типа, добавляя к имени функции имя класса, не забыв про указатель.
Напомню, что ->* используется, когда стоящий слева аргумент представляет собой указатель на объект (как в нашем случае this), а .* -- когда он является ссылкой на объект. Пример обращения к полям и методам через .* приведен ниже:
#include

class A
{
public:
int x;
void func(int y) { std::cout << "y = " << y << std::endl; }

typedef int A::*pointer_to_member;
typedef void (A::*pointer_to_function) (int);
};


int main()
{
A a;

A::pointer_to_member ptrToMember = &A::x;
A::pointer_to_function ptrToFunction = &A::func;

a.*ptrToMember = 10;
std::cout << "x = " << a.*ptrToMember << std::endl;

(a.*ptrToFunction) (20);
}

Возьмите себе за правило: как только нужно создать указатель на функцию -- использовать typedef. Всегда.
Для упрощения громоздких вызовов вроде
можно использовать макросы. Например, такой:
#define CALL_MEMBER_FN(ptrToObject,ptrToMember) ((ptrToObject)->*(ptrToMember))

Тогда указанный выше вызов запишется как
Это тот случай, когда использование макросов полезно.
Дмитрий Храмов
Компьютерное моделирование и все, что с ним связано: сбор данных, их анализ, разработка математических моделей, софт для моделирования, визуализации и оформления публикаций. Ну и за жизнь немного.
© 2009—2020 Дмитрий Храмов · При поддержке pelican-bootstrap3, Pelican, Bootstrap

Передаем указатели на функции -члены в C API / Хабр
Указатели на функции -члены класса - dkhramov.dp.ua
Указатель на функцию -член класса - C++ - Киберфорум
Указатели на функции члены класса
Указатели на функции -члены... / GameDev.ru — Разработка игр
Мы зарегистрировали подозрительный трафик исходящий из вашей сети.
С помощью этой страницы мы сможем определить, что запросы отправляете именно вы, а не робот.

Порнот В Офисе
Девушку Трахают Дилдами
Обвисшие Сиськи Фото
Порнушка Смачная
Вагинальный Фистинг Полный

Report Page