2010-04-04 10 views
7

Faccio regolarmente uso di dichiarazioni di classe forward e puntatori a tali classi.Qualsiasi modo in C++ di inoltrare dichiara un prototipo di funzione?

Ora ho bisogno di passare un puntatore di funzione attraverso un numero di livelli. Preferirei includere l'intestazione che dichiara il prototipo del mio puntatore di funzione solo nel modulo che dereferisce un puntatore a funzione piuttosto che in ogni livello che passa semplicemente lungo quel valore di puntatore.

È possibile?

=====

Dalle risposte ho il sospetto che non ho espresso dalla domanda con sufficiente chiarezza. Cerco un analogo a una dichiarazione di classe avanzata. Siamo tutti d'accordo che posso scrivere:

classe foo;

void bar (foo *);

void waz (foo * p) {bar (p); }

Si noti che waz non sa nulla di classe foo diverso dal suo nome. Forse la bar avrà accesso alla descrizione completa di foo. Forse la barra passerà semplicemente p più avanti. Che importa? Solo quei siti che dereferiscono un foo *. Tutti gli altri siti hanno bisogno solo di "classe foo".

Allo stesso modo so che posso scrivere:

typedef void foo (int, double);

void bar (foo *);

void waz (foo * p) {bar (p); }

La differenza è che ora l'identificatore foo non solo è noto per denotare un tipo di funzione, ma inoltre porta già la firma completa/prototipo. Questo mi costringe in uno dei due spiacevoli scenari:

1) clonare il typedef su più siti (yuck! Fragile!) 2) incollare il typedef in un'intestazione e includerlo ovunque sia menzionato un foo *.

Nota l'asimmetria: nel caso di un oggetto di dati, dovevo solo fornire una descrizione completa della classe foo in quei punti in cui voglio dereferenziare un foo *; nel caso di una funzione ho bisogno di fornire la firma/prototipo completo ovunque io voglia menzionare un foo *.

Quindi c'è comunque da rimediare a questa asimmetria?

+0

Non c'è asimmetria. È possibile inoltrare una classe e una funzione, non un typedef. Un typedef è solo un alias, non esiste più al momento del collegamento, quindi non c'è nulla da inoltrare per dichiararlo. –

+0

La tua argomentazione è fallace. Sì, se utilizzato deve esistere una funzione al momento del collegamento o si ottiene un errore di simbolo non definito. OTOH una classe dichiarata in avanti non lo fa. Le istanze di tale classe possono esistere ma non sono ciò che un nome di classe dichiarato avanti indica. Un nome di classe dichiarato in avanti denota una classe, non un oggetto che occupa memoria. –

+0

"_Un nome di classe dichiarato avanti denota un ** [tipo] **, non un oggetto che occupa memoria._" Proprio come un puntatore a funzione denota un ** tipo **, non una funzione che occupa istruzioni (e un punto di ingresso) in il programma. Il mio punto è che non si tratta del 'typedef'; questo è irrilevante. –

risposta

-1

Totalmente possibile. Puoi copiare il tuo prototipo di funzione ovunque ti serva, anche se quando lo vedo molto, i campanelli d'allarme iniziano a suonare.

3

Per passare puntatori a funzione solamente necessario conoscere i tipi di argomento e il tipo di ritorno:

void f(void (*func)(int)); 

Qui, f() è una funzione che prende un puntatore a funzione a una funzione che prende un int e restituisce void.

typedef s fanno si che più leggibile:

typedef void (*FuncPtr)(int); 
void f(FuncPtr func); 

In generale si potrebbe desiderare di guardare funtori o utilizzando per esempio Boost.Function e Boost.Bind. In questo modo si può anche passare nelle funzioni membro vincolato o funzione di oggetti:

void f(boost::function<void (int)> fn) { 
    fn(42); 
} 

struct X { 
    void f(int) {} 
}; 

// ... 
X x; 
f(boost::bind(&X::f, &x, _1)); 
0

Certo, per esempio

typedef void (*FOOFUNC)(int x, int y, char z); 

Ora è possibile passare intorno

void foo(FOOFUNC f) { 
    f(...); 
} 
+0

Come è una dichiarazione in avanti? È un semplice typedef, non è vero? – Zoso

4

È possibile farlo utilizzando un tipo di struttura indefinita, al costo di un dereference supplementare.

mettere questo nel file di intestazione principale:

typedef struct FuncStruct *FuncPtr; 

Questo dichiara struct FuncStruct ma non dichiara alcun campo, allora dichiara un puntatore a questa struct chiamato FuncPtr. Puoi passare FuncPtr s in giro ma non puoi dereferenziarli.

poi in un particolare file (o un file .h più specifica), si può effettivamente definire un struct FuncStruct come questo:

struct FuncStruct { 
    int (*f)(int, char, double); 
}; 

Poi codice passato questa definizione può dereference un FuncPtr per ottenere il puntatore a funzione reale .

Nota questo è un extra dereferenziamento da un cast e significa che è necessario eseguire una gestione della memoria di FuncStruct s.

-1

Non è chiaro dalla tua domanda che cosa stai facendo.

In primo luogo, non esiste un prototipo in C++. Il concetto di "prototipo" (prototipo di funzione) è specifico solo per il linguaggio C.

In secondo luogo, si menziona un "prototipo di puntatore di funzione" nel corpo del messaggio, mentre la didascalia parla di "prototipo di funzione". Questo lo rende ancora più confuso. "Il prototipo del puntatore di funzione" non ha senso. Non esiste un "prototipo" per un puntatore, nemmeno in C, per non parlare del C++.

Allora, che cosa vuoi fare? Se vuoi inoltrare - dichiarare una funzione - basta dichiararla.

Se si desidera inoltrare un puntatore, anche solo dichiararlo. Per ottenere una dichiarazione (una dichiarazione non definita) di un oggetto, basta dichiararlo con una parola chiave extern.

0

Capisco esattamente cosa l'OP sta cercando di fare. In effetti, voglio fare la stessa cosa. A seguito di ciò che il PO ha detto, ho il seguente (in C, C++ non):

/* File A.h */ 
typedef void (*f_t)(int x); 

/* File B.h */ 
typedef void (*call_f_t)(f_t func2call,int y); 

La domanda è, fa B.h devono includere A.h? A.h definisce tutti i tipi di altre cose che preferirei non includere in B.h', so I am hoping is a way to "forward reference" a function pointer, without redefining it in a typedef in B.h` (che probabilmente non funziona nemmeno)?

Oppure il compilatore deve sapere di più su f_t in B.h rispetto a, ad esempio, un riferimento in avanti struct?

È anche possibile che io debba ripensare il layout del mio codice, ma sono d'accordo con l'OP, che in un mondo perfetto, ci dovrebbe essere una sorta di simmetria tra i puntatori di funzione e altri oggetti che possono essere inoltrati- riferimento.

+1

Puoi usare qualsiasi puntatore di funzione al posto del puntatore della funzione reale, come 'void (*)()'. Lo standard garantisce che i puntatori di funzione di qualsiasi tipo siano convertibili in qualsiasi altro tipo. – BeeOnRope

Problemi correlati