Puntatori a funzioni





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:

Puntatori a funzioni
4.4 (88%) 5 voti

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.

15 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 (e radicalmente diverse l'una dall'altra). E solo nella rappresentazione macchina interna di un puntatore a una funzione, un metodo di classe, diciamo, и char * – già non si discostano, semplicemente indistinguibili.

      1. > certamente aggiunge. perché, in termini di tipizzazione C, in particolare C ++, sintatticamente "affronta semplicemente" o "determinati indirizzi" non esiste affatto (tranne che, ad eccezione void *). Tutti i puntatori digitati … E solo nella rappresentazione macchina interna di un puntatore a una funzione, un metodo di classe, diciamo, e char * - già non differiscono, semplicemente indistinguibili.

        indirizzo – anche in Africa indirizzo, indipendentemente da ciò che si scrive.

        #includere

        int main() {
        int val = 12345;
        int * INTP = &val; // tipo di puntatore tipizzato
        char * Charp; // Un altro puntatore tipizzato
        Crp = (char *)INTP;

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

        Qui si dimostra che puntatore int può essere lanciato a un puntatore 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. Nel secondo caso, char * viene colata a int * puntatore dereference e, pertanto, già preso tutti 4 byte.

        conclusione: 57 12345

        In ogni caso, con indirizzi in C, si può lavorare come si desidera. Si può prendere i dati da qualsiasi indirizzo, leggere e scrivere su di loro tutto ciò.

        Per esempio si potrebbe aggiungere alla fine di questo programma, qualcosa di simile:
        *Crp = 56;

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

        cioè, l'indirizzo della val può essere sostituito con il primo byte, lavorare con lui tramite un puntatore char. E non si può primo byte, dal momento che in C tutto va bene con l'indirizzo aritmetica.

    2. > L'ultimo esempio è noiosa. IMHO su puntatori a funzioni avuto

      Ma in questa occasione: non “ho avuto” – ed è stato necessario prendere e come scrivere il testo, e suoi esempi. E non dire triste “come avrebbe dovuto essere”.

      1. Scrivo “i loro testi” :). Dalla critica con calma. Soprattutto quando quel, che hai imparato non può essere ottenuto.

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

        “Il contesto della nostra discussione” – esso “puntatori a funzione” e in essa non ci chiediamo che cosa sta succedendo con le librerie condivise.

        a fortiori, che l'accuratezza delle informazioni che potrebbero essere in dubbio. che dici, quel programma C ++ utilizzando “libreria condivisa” linguaggio C. termine “libreria condivisa” suggerisce, libreria che viene utilizzato contemporaneamente da più processi.

        duck, La libreria include all'interno di ogni file eseguibile, non lo fanno nifiga “diviso”. Come hanno condiviso può essere utilizzato per il debug, ma rilascia stanno andando con l'opzione –static sempre. In caso contrario, il programma non verrà eseguito sul computer, se non è installata la stessa versione del compilatore, che è stato utilizzato durante l'assemblaggio del programma e non saranno registrati corrispondente al modo in cui il percorso di sistema. Oppure si può, naturalmente, eseguire tutti i programmi, scritto in C ++ da una directory, in cui il luogo radice appropriato DLL / .so, ma nessun altro lo fa

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

        Questo tipo di costruzione in grado intero. anzi, è selvaggiamente inefficiente e può essere sostituito con le funzioni standard. Dal momento che è anche un valore negativo cade OP2.

        PS. Se si scrive un articolo sui puntatori a funzione in C ++, IMHO è necessario raccontare std::funzionale. C lato ode rivendicato titolo C ++, non la sua. D'altra – funtional quasi ogni punto di vista è migliore e più conveniente. Per esempio sono stato attraverso di essa può trasmettere lambda (Sì, e qualsiasi altro oggetto callable), e attraverso un puntatore a funzione – non può.

        Invece, l'autore ha scritto alcune informazioni non corrette su “libreria condivisa”.

      3. Sono assolutamente d'accordo con la seguente commentatore, lezioni che non si ottiene.

  2. int main()
    {
    //…
    ritorno 0; // già 4 Quest'anno una linea aggiuntiva. Se il programma non è terminata in modo anomalo, * * Restituisce automaticamente il codice di errore pari a zero. vale a dire. siete qui per svolgere un lavoro, che senza di te il compilatore esegue

    >> 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):

    In questa situazione, in ogni caso non è possibile farlo, si scrive. Tutti i vostri sforzi sono ben lungi dall'essere selvatici “sviluppo attraverso test”. Посмотри на quadro di prova di Google или на spinta framework di unit test или на 100500 analoghi.

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

    articolo di genere si parla di “intelligente compilatore”. In realtà non c'è nulla di particolarmente intelligente non è – Se il nome della funzione non è una parentesi, stopudovo non è una chiamata di funzione, e un puntatore ad esso. Nessun tipo di pervertito &I funzione ovunque, ma il tuo articolo non ho visto.

  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 non introduce un nuovo tipo di, definisce solo a breve sinonimo per lungo tempo la scrittura “un puntatore a una funzione qui questo tipo”.
      A più determinato schieramento questi puntatori a funzione (chiamato UFPER) e lui subito in modo chiaro inizializzato. Poiché l'uscita del inizializzazione dell'array, quando si tenta di descriverlo, non possiamo specificare ([]).

  4. comprensibilmente, che sizeof restituisce la lunghezza in byte, ma la condizione:
    io < taglia di(test) / taglia di(test[0])
    Non riesco a capire. spiegare pzhl.

    1. Che cosa potrebbe essere più semplice?
      Come accade il numero di elementi dell'array.
      Se un array di elementi 1 byte (carbonizzare[]) contiene 10 elemento, è 10/1 = 10.
      Se gli elementi dell'array 100 byte (strutture)contiene 10 elemento, è 1000/100 = … e di nuovo 10.

      1. Dare un sacco di problemi sono stati sugli argomenti di questo sito…grazie per le lezioni!

Lascia un Commento

L'indirizzo email non verrà pubblicato. i campi richiesti sono contrassegnati *