Pointeurs de fonctions

Pointeurs de fonctions
4 (80%) 1 vote





un pointeur de fonction, с++, Programmation pour les débutants, c++c ++

Il a été observé, que les pointeurs peuvent pointer vers une variété de types d'objets dans le langage de programmation C ++. plus précisément, à tous et sur toutes sortes d'objets, Les données du programme sont.

Cependant, les mêmes objets, sous forme d'objets de données conventionnelles, sont fonctions dans le programme. De là naît un désir d'essayer de définir et d'utiliser un pointeur de fonction. Créer ce programme simple (ex1.cc):

Ici, la fonction région() tout clair: il calcule l'aire d'un cercle de rayon, qui est consacré à sa, en tant que paramètre. Mais plus tard, nous déclarons un pointeur variable à une fonction:

Au moment de cette annonce, le pointeur pfunc Il n'y a rien de plus, une autre adresse dans la représentation informatique interne (4 Byte système d'exploitation 32 bits,, 8 Byte système d'exploitation 64 bits,). Ceci est exactement le même genre de interne, qui a, disons, un pointeur vers une variable entière int *. Cependant, cet indice a un type strictement défini: un pointeur de fonction, prend un paramètre de type double, et renvoie une valeur de type double. Mais sur quels points la fonction de pointeur spécifiques, à sa définition - peu importe: la valeur de l'index n'a pas été défini.

Mais le prochain opérateur d'affectation, nous lier un pointeur de fonction à une fonction particulière région(). Absolument correct serait d'enregistrer l'attribution des adresses de pointeur de fonction: pfunc = &région. Mais le compilateur C est assez intelligent, qui référence le nom de la fonction dans l'instruction d'affectation interprète comme son adresse. Ainsi l'entrée pfunc = zone aussi tout à fait correct. De ce point, nous pouvons utiliser le pointeur pfunc pour appeler une fonction à laquelle il pointe. Pour ce faire, nous écrivons la valeur à laquelle les points de pointeur *pfunc (opération * Dans ce contexte, il est appelé déréférencer aiguille). Les parenthèses autour de la valeur déréférencé pfunc enregistrement (*pfunc)( r ) nécessaire pour des raisons de priorité des opérations en matière de divulgation. Exécution cet exemple:

un pointeur de fonction, с++, Programmation pour les débutants, c++c ++

Bien que l'utilisation des pointeurs de fonction n'a rien apporté de fondamentalement nouveau dans cet exemple,, à part quelques subtilités de syntaxe. Mais dans cet exemple, nous avons encore ne savons comment définir et utiliser des pointeurs de fonction. Et maintenant, nous pouvons passer à la question de savoir pourquoi il est nécessaire et comment nous pouvons l'utiliser.

supposant, pour un grand projet, nous préparons une série de tests, выполняемых в процесс развития и роста самого тестируемого проекта (это так называемая технология разработки тестирования, и очень продуктивная). Le nombre de tests tour par tour dans cette situation va continuer à croître alors que nous allons de préparation du projet de base.

Dans cette situation, nous pouvons le faire (ex2.cc):

И вот что мы имеем на исполнении:

un pointeur de fonction, с++, Programmation pour les débutants, c++c ++

В этом листинге tests[ ] – il tableau указателей на функции без параметров и без возвращаемых значений. Красивое решение, не правда ли? Nous ne pouvons pas hésiter à ajouter de nouvelles fonctionnalités causées par essai solide, et chacun d'entre eux seront appelés dans l'ordre lors de l'exécution.

Nous pouvons aller encore plus loin: если указатель на функцию представляет функцию в выражениях, можно передать указатель на функцию в качестве параметра другой, охватывающей функции, и последняя будет выполнять в своём теле переданную параметром функцию, не зная какое действие при этом выполняется.

Для иллюстрации всего сказанного создадим программу самого примитивного калькулятора, выполняющего арифметические действия над целочисленными операндами (ex3.cc):

Здесь собственно вычисление выполняет функция calculer(). Но она ничего не «знает» о выполняемых действиях и о арифметических операциях вообще: on applique au deuxième de la première de ses paramètres 6 fonctions, qu'elle a remis au 3ème paramètre pour effectuer.

Qui ne connaît pas typedef lire ici.

Cette fonction de code strtod() – une caractéristique standard de la bibliothèque C (ANSI C, стандарта POSIX), которая извлекает десятичное число из строки, полученной со стандартного потока ввода. В контексте наших обсуждений это интересно тем, que:

  • программа на C++ может использовать всё множество библиотечных вызовов языка C;
  • программа C++ использует на этапе выполнения разделяемые библиотеки языка C (.so ou .dll), и при отсутствии стандартной библиотеки C, программы на C++ становятся неработоспособными.

Но вернёмся к работе показанного калькулятора (его предельная упрощённость связана с тем, что мы не занимаемся проблемами ввода, его формата и не обрабатываем ошибки ввода пользователемв реальных программах так делать нельзя):

un pointeur de fonction, с++, Programmation pour les débutants, c++c ++

Наблюдательный читатель мог бы заметить, que la fonction calculer() при всём своём желании и не могла бы выполнить ни одно из требуемых арифметических действий, так как выполняющие эти действия функции somme(), dif(), moi() et div() описаны позже fonctions calculer() и не видимы в коде функции calculer().

ainsi, мы рассмотрели несколько различных случаев, когда функции в C++ используются, как экземпляры данных. Они могут объединяться в массивы, встраиваться в качестве полей structures, или передаваться другим функциям в качестве параметров. Все эти и подробные возможности реализуются за счёт указателей на функции (хотя по синтаксису записей они могут и не выглядеть как указатели, за счёт умного компилятора C++, который по контексту понимает, что должны использоваться адреса функций).

Если вам что-то не понятно по материалу или по коду программ – poser des questions dans les commentaires.

Предлагаем вам оценить этот урок и урок Указатели на объекты:

Bulletin de nouvelles leçons sur la programmation:

huile

Sur huile

une expérience pratique sur le développement de logiciels 40 ans. société de logiciels internationale Global Teacher Logic. IBM Developer Works auteur permanent des publications. éditeur scientifique de l'ordinateur littérature maison d'édition "Symbole-Plus", Saint-Pétersbourg.

14 réflexions sur "Pointeurs de fonctions

  1. Лишняя точка с запятой в первом листинге после функции double area(double R).

    некоторый адрес во внутреннем представлении компьютера
    juste “некоторый адрес”, к чему эта добавка провнутреннее представление”? – она что-то добавляет к сути?

    нового в рассматриваемом примерt
    опечатка.

    можно передать указатель на функцию в качестве параметра другой, охватывающей функции, ”
    Что за охватывающая функция? Что она охватывает?

    Кто не знает о typedef – читайте тут.
    Ссылка замечательная, но лучше написать про это тут (это же совсем не много).

    Последний пример унылый. ИМХО по теме указателей на функции надо было сказать про это вцелом (как в первом примере статьи), потом привести пример с стандартной функцией qsort, которая принимает указатель на функцию сравнения элементов. Ну и завершить все чем-то вроде функции поиска корня методом половинного деления (это очень простой пример и в нем точно также как в qsort удобно передавать функцию в качестве параметра).

    à savoir. юзер должен увидеть что есть указатели на функции и разобраться с синтаксисом (в первый пример можно добавить описание typedef). Затем увидел, что это реально нужно (раз используется в стандартной библиотеке). Ну и под конец научился писать такие же функции, принимающие другие функции по указателю, как и qsort.

    Ну это ИМХО.

    1. > Просто “некоторый адрес”, к чему эта добавка про “внутреннее представление”? – она что-то добавляет к сути?

      Конечно добавляет. Потому как, с точки зрения типизации C, а особенно C++, синтаксическипросто адресов” ou “некоторых адресовне существует вообще (разве что исключая void*). Все указатели типизированные (и тем радикально различаются друг от друга). И только во внутреннем машинном представлении указатель на функцию-метод класса, disons, и char*уже ничем не различаются, они просто неразличимы.

      1. > Конечно добавляет. Потому как, с точки зрения типизации C, а особенно C++, синтаксически “просто адресов” или “некоторых адресов” не существует вообще (разве что исключая void*). Все указатели типизированныеИ только во внутреннем машинном представлении указатель на функцию-метод класса, disons, и char* – уже ничем не различаются, они просто неразличимы.

        Адресон и в Африке адрес, независимо на чем ты пишешь.

        #comprendre

        int main() {
        int val = 12345;
        int *intp = &val; // типа типизированный указатель
        char *charp; // еще один типизированный указатель
        charp = (carboniser*)intp;

        std::cout << (int) *charp << " " << *(int *)charp << std::endl;
        }

        Тут показано что указатель на int можно скастовать в указатель на char.
        Eh bien, vous pouvez vous référer à ces données d'adresse. Dans le premier cas, déréférencé pointeur char *, de sorte que le premier octet est sélectionnée par l'adresse de val. Во втором случае указатель char* кастуется в int* и разыменовывается, поэтому берутся уже все 4 octet.

        conclusion: 57 12345

        В любом случае с адресами в Си можно работать как угодно. Ты можешь брать данные по любому адресу, lire et les écrire quoi que ce soit.

        Par exemple, vous pourriez ajouter à la fin de ce programme, quelque chose comme:
        *charp = 56;

        std::cout << val << std::endl;

        autrement dit, l'adresse peut être remplacée par la variable val premier octet, работая с ним через указатель на char. А можно и не первый байт, ведь в Си все хорошо с адресной арифметикой.

    2. > Последний пример унылый. ИМХО по теме указателей на функции надо было

      А вот по этому поводу: pas “надо было” – а надо было взять и написать как свой текст, так и свои примеры. А не тоскливо рассказыватькак надо бы было бы”.

      1. Я и пишусвои тексты” :). К критике относись спокойней. Особенно при том, что уроки у тебя не получаются.

        >> В контексте наших обсуждений это интересно тем, que: … программа C++ использует на этапе выполнения разделяемые библиотеки языка C (.so или .dll), и при отсутствии стандартной библиотеки C, программы на C++ становятся неработоспособными.

        Контекст наших обсуждений” – il “указатели на функциии в нем нам вообще не интересно что там происходит с разделяемыми библиотеками.

        Тем более, что достоверность этой инфы может вызывать сомнения. Ты говоришь, что программы на С++ используютразделяемые библиотекиязыка Си. Терминразделяемая библиотекапредполагает, что библиотека одновременно используется несколькими процессами.

        Дак вот, библиотеки включаются внутрь каждого исполняемого файла, они нифига неразделяемые”. Как разделяемые они может быть используются при отладке, но релизы собираются с опциейstatic всегда. Иначе твоя программа не запустится на компьютере, если на нем не установлен компилятор той же версии, которую ты использовал при сборке программы и не будут прописаны соответствующие пути в системную переменную PATH. Ну или ты можешь, bien sûr, запускать все программы, написанные на С++ из одного каталога, в корень которого поместить соответствующие .dll/.so, но так никто не делает

      2. int powr(int op1, int op2)
        {
        int ret = 1;
        tandis que (op2–) droite * = op1;
        retour ret;
        }

        Это типа возведение целую в степень. Мало того, что это дико неэффективно и может быть заменено использованием стандартной функции. Так оно еще и упадет при отрицательном значении op2.

        PS. Если писать статью про указатели на функции в С++, то ИМХО стоит рассказать про std::functional. С одой стороны в заголовке заявлено С++, а не Си. С другойfuntional почти со всех точек зрения лучше и удобней. Например я через него могу лямбду передавать (да и любой другой callable объект), а через указатель на функциюне могу.

        Но вместо этого автор написал какую-то недостоверную информацию проразделяемые библиотеки”.

      3. Совершенно согласен со следующим коментатором, уроки у тебя НЕ получаются.

  2. int main()
    {
    //…
    retour 0; // уже 4 года эта строчка лишняя. Если программа не завершилась аварийно, она *автоматически* вернет нулевой код ошибки. à savoir. ты тут выполняешь работу, которую и без тебя выполняет компилятор

    >> supposant, pour un grand projet, nous préparons une série de tests, выполняемых в процесс развития и роста самого тестируемого проекта (это так называемая технология разработки тестирования, и очень продуктивная). … Dans cette situation, nous pouvons le faire (ex2.cc):

    В этой ситуации ни в коем случае нельзя поступать так, как ты пишешь. Все твои старания дико далеки отразработки через тестирование”. Посмотри на google test framework или на boost unit test framework или на 100500 аналогов.

    >>
    pour (int i = 0; je > за счёт умного компилятора C++, который по контексту понимает, что должны использоваться адреса функций

    Пол статьи ты рассказываешь проумный компилятор”. Реально там ничего особо умного нетесли за именем функции нет круглой скобки, то стопудово это не вызов функции, а указатель на нее. Никаких извратов типа &function я нигде кроме твоей статьи не видел.

  3. Как же трудно у меня все обстоит с этими указателями:(
    Интересный урок и заставляет много думать. Наверное это хорошо, mais quelques-uns des faits saillants pour moi sont restés claire. Surtout avec un tableau de pointeurs de fonction, et quelqu'un peut me répondre par typedef.
    typedef int(*fint_t)(int, int);
    OFPER fint_t[] =
    {
    summ, diff, beaucoup, DIVD, Bals, powr
    };
    Voici la vue, что указатель на функцию превращается в тип данных?
    Объясните пожалуйста

    1. typedef не вводит нового типа, он только определяет короткий синоним для длинного написанияуказатель на функцию вот такого типа”.
      А дальше определяется tableau таких указателей на функции (с именем foper) и он тут же явно инициализируется. Поскольку из инициализации выводится размер массива, то при его описании мы можем его не указывать ([]).

  4. naturellement, что sizeof возвращающий длину в байтах, но вот условие:
    je < taille de(tests) / taille de(tests[0])
    никак не могу понять. Поясните пжл.

    1. Что может быть проще?
      Так получается число элементов массива.
      Если массив 1-байтных элементов (carboniser[]) содержит 10 élément, то это 10/1=10.
      Если массив 100-байтных элементов (structures)содержит 10 élément, то это 1000/100=и опять же 10.

Laisser un commentaire

Placez le code dans les balises: <pre class="lang:c ++ décodage:true ">VOTRE CODE</pré>