Puntatori a funzioni

Puntatori a funzioni
4 (80%) 1 vote





un puntatore a funzione, с++, La programmazione per i principianti, c++C ++

È stato osservato, che i puntatori possono indicare una varietà di tipi di oggetti nel linguaggio di programmazione C ++. Più precisamente, a tutti e su tutti i tipi di oggetti, I dati del programma sono.

Tuttavia, gli stessi oggetti, come oggetti di dati convenzionali, sono funzioni nel programma. Di qui il desiderio di cercare di definire e utilizzare un puntatore a funzione. Creare questo semplice programma (ex1.cc):

Qui, con la funzione la zona() cessato allarme: calcola l'area di un cerchio di raggio, che è dedicato a lei, come parametro. Ma più tardi, si dichiara un puntatore variabile a una funzione:

Al momento di questo annuncio, il puntatore pfunc Non è niente di più, come un certo indirizzo nella rappresentazione interna del computer (4 Byte sistema operativo a 32-bit,, 8 Byte sistema operativo a 64-bit,). Questo è esattamente lo stesso tipo di interno, che ha, diciamo, un puntatore a una variabile intera int *. Tuttavia, questo indice ha un tipo rigorosamente definiti: un puntatore a funzione, prende un parametro di tipo raddoppiare, e restituisce un valore di tipo raddoppiare. Ma su ciò che specifici punti di puntatore a funzione, a sua definizione - non importa: il valore dell'indice non è definito.

Ma la prossima operatore di assegnazione si legano un puntatore a funzione di una particolare funzione la zona(). Assolutamente corretta sarebbe quella di registrare l'assegnazione degli indirizzi puntatore a funzione: pfunc = &la zona. Ma il C ++ compilatore è abbastanza intelligente, che fa riferimento il nome della funzione nell'istruzione di assegnazione interpreta come il suo indirizzo. Così entry pfunc = area anche assolutamente corretto. Da questo punto siamo in grado di utilizzare il puntatore pfunc chiamare una funzione a cui punta. Per fare questo, scriviamo il valore a cui punta il puntatore *pfunc (operazione * in questo contesto si chiama dereference pointer). Le parentesi attorno al valore Dereferenced pfunc registrazione (*pfunc)( R ) necessaria per ragioni di priorità delle operazioni in termini di disclosure. L'esecuzione di questo esempio:

un puntatore a funzione, с++, La programmazione per i principianti, c++C ++

Mentre l'uso di puntatori a funzione non ha portato nulla di fondamentalmente nuovo in questo esempio,, a parte qualche complessità della sintassi. Ma in questo esempio, sappiamo ancora solo come definire e utilizzare puntatori a funzione. E ora siamo in grado di passare alla questione del perché è necessario e come possiamo usarlo.

ammesso che, per un grande progetto, stiamo preparando una serie di test, eseguita nel processo di sviluppo e crescita del progetto di test (la cosiddetta tecnologia sviluppo di test, e molto produttiva). Il numero di test di turni in questa situazione continuerà a crescere, mentre ci muoviamo disponibilità del progetto di base.

In questa situazione, siamo in grado di farlo (ex2.cc):

E questo è ciò che abbiamo sulle prestazioni:

un puntatore a funzione, с++, La programmazione per i principianti, c++C ++

In questo elenco test[ ] – esso schieramento puntatori a funzione senza parametri e nessun valore di ritorno. bella soluzione, non è vero?? Non possiamo esitare ad aggiungere nuove funzionalità causati dalla prova solida, e tutti saranno chiamati in sequenza quando si esegue.

Siamo in grado di andare anche oltre: se la funzione è un puntatore a una funzione in un'espressione, È possibile passare un puntatore a funzione come parametro ad un altro, funzione abbracciando, e quest'ultimo si esibiranno in la funzione del corpo per passare i parametri, non sapendo che viene eseguita un'azione allo stesso tempo.

Per illustrare quanto detto il programma crea il calcolatore più primitivo, eseguire operazioni aritmetiche su operandi interi (ex3.cc):

Si esegue la funzione calcolo effettivo calcolare(). Ma lei non "conoscere" nulla delle azioni svolte e tutte le operazioni aritmetiche: si applica alla 2a primo dei suoi parametri 6 funzioni, che ha consegnato al 3 ° parametro per eseguire.

Chi non conosce su typedef leggi qui.

Questa funzione di codice strtod() – una caratteristica standard della libreria C (ANSI C, standard POSIX), che estrae un numero decimale da una stringa, ottenuto dal flusso di input standard. Nel contesto della nostra discussione è interessante perché, che:

  • un programma C ++ possono utilizzare l'intero set di chiamate di libreria C;
  • programma in C ++ usando runtime condivisa libreria C (.così o .dll), e in assenza di una libreria standard C, programmi C ++ sono inoperanti.

Ma torniamo alla calcolatrice mostrato (sua estremamente semplificato per il fatto, che noi non trattiamo con i problemi di ingresso, il suo formato e non elaborare gli errori di input dell'utente – in applicazioni reali, quindi non si può fare):

un puntatore a funzione, с++, La programmazione per i principianti, c++C ++

lettore attento avrà notato, che la funzione calcolare() nonostante tutto il loro desiderio e non poteva eseguire una delle operazioni aritmetiche richieste, oltre a svolgere queste funzioni azioni somma(), DIF(), me() e div() descritto dopo funzioni calcolare() non visibile nel codice funzione calcolare().

così, Abbiamo esaminato diverse occasioni, quando le funzioni sono utilizzati in C ++, come elementi di dati. Essi possono essere combinati in array, integrato come campi strutture, o trasferiti ad altre funzioni come argomenti. Tutti questi dettagli e possibilità sono realizzati a spese di puntatori a funzione (Anche se non può sembrare come record di sintassi puntatori, a causa della intelligente compilatore C ++, che capisce il contesto, che dovrebbe essere usato indirizzi funzioni).

Se non capite qualcosa sul materiale o dei programmi in codice – porre domande nei commenti.

Vi invitiamo a valutare questa lezione e lezione Puntatori a oggetti:

Newsletter nuove lezioni sulla programmazione:

olio

Di olio

esperienze pratiche circa lo sviluppo del software 40 anni. Maestro globale Logic società di software internazionale. IBM Developer funziona autore permanente di pubblicazioni. redattore scientifico del computer casa editrice letteratura "Simbolo-Plus", San Pietroburgo.

14 pensieri su "Puntatori a funzioni

  1. Il punto e virgola in più nel primo elenco dopo l'area doppia funzione(double R).

    “un indirizzo nella rappresentazione interna del computer”
    solo “un indirizzo”, che dire di questo supplemento “rappresentazione interna”? – aggiunge qualcosa al punto?

    “Novità di questa primert”
    errore di battitura.

    “È possibile passare un puntatore a funzione come parametro ad un altro, funzione abbracciando, ”
    Qual è la funzione di coprire? Che copre?

    “Chi non conosce il typedef - leggere qui.”
    collegamento eccellente, ma è meglio scrivere su di esso qui (non è molto).

    L'ultimo esempio è noiosa. IMHO su puntatori a funzione hanno da dire in proposito nel suo complesso (come nel primo esempio articolo), Poi dare un esempio di una funzione qsort di serie, che prende un puntatore a una funzione di confronto. E per completare tutto qualcosa come la funzione di ricerca della radice da bisection (questo è un esempio molto semplice, ed altrettanto comoda da passare qsort funzione come parametro).

    vale a dire. l'utente deve vedere che ci sono puntatori a funzioni e trattare con la sintassi (Nel primo esempio, è possibile aggiungere una descrizione typedef). Poi ho visto, E 'davvero necessario (una volta utilizzato nella libreria standard). Ebbene, alla fine ho imparato a scrivere le stesse funzioni, prendere altro puntatore a funzione, come qsort.

    Bene, questo è IMHO.

    1. > Solo "un indirizzo", al quale questo supplemento di "rappresentazione interna"? - Si aggiunge qualcosa al punto?

      certamente aggiunge. perché, in termini di tipizzazione C, in particolare C ++, sintatticamente “semplicemente indirizzi” o “alcuni indirizzi” in generale, non vi è (tranne che, ad eccezione void *). Tutti i puntatori tipizzati (и тем радикально различаются друг от друга). И только во внутреннем машинном представлении указатель на функцию-метод класса, diciamo, и char*уже ничем не различаются, они просто неразличимы.

      1. > certamente aggiunge. perché, in termini di tipizzazione C, in particolare C ++, синтаксически “просто адресов” или “некоторых адресов” не существует вообще (tranne che, ad eccezione void *). Все указатели типизированныеИ только во внутреннем машинном представлении указатель на функцию-метод класса, diciamo, и char* – уже ничем не различаются, они просто неразличимы.

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

        #includere

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

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

        Тут показано что указатель на int можно скастовать в указатель на char.
        Bene, allora si può fare riferimento a questo indirizzo i dati. Nel primo caso, dereferenziati puntatore char *, quindi il primo byte è selezionata per l'indirizzo di val. Во втором случае указатель char* кастуется в int* и разыменовывается, поэтому берутся уже все 4 byte.

        conclusione: 57 12345

        В любом случае с адресами в Си можно работать как угодно. Ты можешь брать данные по любому адресу, считывать их и записывать по ним что угодно.

        Например ты мог бы дописать в конец этой программы что-то типа:
        *charp = 56;

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

        то-есть по адресу переменной val можно заменить первый байт, работая с ним через указатель на char. А можно и не первый байт, ведь в Си все хорошо с адресной арифметикой.

    2. > L'ultimo esempio è noiosa. ИМХО по теме указателей на функции надо было

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

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

        >> Nel contesto della nostra discussione è interessante perché, che: … programma in C ++ usando runtime condivisa libreria C (.so или .dll), e in assenza di una libreria standard C, programmi C ++ sono inoperanti.

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

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

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

      2. int powr(int op1, int op2)
        {
        int ret = 1;
        mentre (op2–) destra * = op1;
        ret ritorno;
        }

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

        PS. Если писать статью про указатели на функции в С++, то ИМХО стоит рассказать про std::functional. С одой стороны в заголовке заявлено С++, а не Си. С другойfuntional почти со всех точек зрения лучше и удобней. Например я через него могу лямбду передавать (Sì, e qualsiasi altro oggetto callable), e attraverso un puntatore a funzione – non può.

        Invece, l'autore ha scritto alcune informazioni non corrette su “разделяемые библиотеки”.

      3. Sono assolutamente d'accordo con la seguente commentatore, уроки у тебя НЕ получаются.

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

    >> ammesso che, per un grande progetto, stiamo preparando una serie di test, eseguita nel processo di sviluppo e crescita del progetto di test (la cosiddetta tecnologia sviluppo di test, e molto produttiva). … In questa situazione, siamo in grado di farlo (ex2.cc):

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

    >>
    per (int i = 0; io > a causa della intelligente compilatore C ++, che capisce il contesto, che dovrebbe essere usato indirizzi funzioni

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

  3. Quanto è difficile tutto questo è che ho con questi puntatori:(
    Una lezione interessante e fa un sacco di pensiero. Credo che sia buono, ma alcuni dei punti salienti per me sono rimasti poco chiari. Soprattutto con una serie di puntatori a funzione, e qualcuno mi può rispondere attraverso typedef.
    typedef int(*fint_t)(int, int);
    UFPER fint_t[] =
    {
    summ, diff, molto, divd, Bals, powr
    };
    Ecco la vista, che la funzione del puntatore si trasforma in un tipo di dati?
    spiegare per favore…

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

      1. Благодарю за ответ! Вроде разобрался!

  4. comprensibilmente, что sizeof возвращающий длину в байтах, но вот условие:
    io < taglia di(test) / taglia di(test[0])
    никак не могу понять. Поясните пжл.

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

Lascia un Commento

Inserire il codice nei tag: <pre class="lang:C ++ decodifica:true ">IL TUO CODICE</pre>