2010-04-04 7 views
7

Hago un uso regular de las declaraciones de clases avanzadas y punteros a dichas clases.Cualquier forma en C++ para reenviar declarar un prototipo de función?

Ahora tengo la necesidad de pasar un puntero a través de varias capas. Preferiría incluir el encabezado que declara el prototipo de mi puntero de función solo en el módulo que desreferencia un puntero de función en lugar de en cada capa que simplemente pasa a lo largo de ese valor de puntero.

¿Esto es posible?

=====

De las respuestas que sospecho que no me he expresado con suficiente claridad por la pregunta. Busco un análogo a una declaración de clase forward. Todos estamos de acuerdo en que puedo escribir:

class foo;

void bar (foo *);

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

Observe que waz no sabe nada acerca de la clase foo aparte de su nombre. Quizás bar tendrá acceso a la descripción completa de foo. Quizás bar simplemente pase p más adelante. ¿A quien le importa? Solo aquellos sitios que eliminan la referencia de un foo *. Todos los demás sitios solo necesitan "clase foo".

mismo modo que sé que puedo escribir:

typedef void foo (int, double);

void bar (foo *);

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

La diferencia es que ahora el identificador foo no solo es conocido por denotar un tipo de función, sino que además lleva la firma/prototipo completo. Esto me obliga a uno de los dos escenarios desagradables:

1) clonar typedef en varios sitios (yuck! Fragile!) 2) pegar el typedef en un encabezado e incluirlo en todas partes donde se menciona un foo *.

Observe la asimetría: en el caso de un objeto de datos, solo necesitaba proporcionar una descripción completa de la clase foo en esos puntos en los que quiero desreferenciar un foo *; en el caso de una función, necesito proporcionar la firma/prototipo completo donde quiera mencionar un foo *.

¿Hay alguna forma de remediar esta asimetría?

+0

No hay asimetría. Puede reenviar declarar una clase y una función, no un typedef. Un typedef es solo un alias, ya no existe en el momento del enlace, por lo que no hay nada que enviar declarar al respecto. –

+0

Tu argumento es falaz. Sí, si se usa, una función debe existir en el momento del enlace o si recibe un error de símbolo indefinido. OTOH una clase declarada avanzada no lo hace. Las instancias de dicha clase pueden existir, pero no son lo que denota un nombre de clase declarado adelante. Un nombre de clase declarado adelante denota una clase, no un objeto que ocupa almacenamiento. –

+0

"_ Un nombre de clase declarado hacia adelante denota un ** [tipo] **, no un objeto que ocupa almacenamiento._" Al igual que un puntero a función denota un ** tipo **, no una función que ocupa instrucciones (y un punto de entrada) en el programa. Mi punto es que no se trata de 'typedef'; eso es irrelevante –

Respuesta

-1

Totally possible. Puedes copiar tu prototipo de función donde lo necesites, aunque cuando veo esto mucho, las alarmas comienzan a sonar.

3

Para pasar punteros de función sólo necesita saber los tipos de argumentos y el tipo de retorno:

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

Aquí, f() es una función que toma un puntero de función a una función que toma un int y devuelve void.

typedef s hacen que sea más legible:

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

En general es posible que desee mirar a funtores o usando, por ejemplo, Boost.Function y Boost.Bind. De esta forma, también puede pasar funciones de miembro o objetos de función vinculados:

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

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

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

Claro, p.

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

Ahora se puede pasar alrededor

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

¿Cómo es eso una declaración directa? Eso es un typedef simple, ¿no? – Zoso

4

Usted puede hacer esto utilizando un tipo de estructura indefinida, a costa de un desreferenciar adicional.

poner esto en el archivo de encabezado principal:

typedef struct FuncStruct *FuncPtr; 

Esto declara struct FuncStruct pero no declaran ningún campo, entonces se declara un puntero a esta estructura llamada FuncPtr. Puedes pasar FuncPtr s pero no puedes desreferenciarlos.

a continuación en un archivo en particular (o un archivo .h más específica), en realidad se puede definir un struct FuncStruct así:

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

Luego código más allá de esta definición puede eliminar la referencia de un FuncPtr para obtener el puntero de función real .

Tenga en cuenta que esto es una desreferencia adicional de solo un molde, y significa que tendrá que hacer un poco de gestión de memoria de FuncStruct s.

-1

No está claro por su pregunta lo que está intentando hacer.

En primer lugar, no existe el "prototipo" en C++. El concepto de "prototipo" (prototipo de función) es específico para el lenguaje C solamente.

En segundo lugar, menciona un "prototipo de puntero a la función" en el cuerpo del mensaje, mientras que el título se refiere al "prototipo de función". Esto lo hace aún más confuso. El "prototipo del puntero de función" no tiene sentido. No hay tal cosa como "prototipo" para un puntero, incluso en C, y mucho menos en C++.

Entonces, ¿qué es lo que quieres hacer? Si quieres reenviar-declarar una función, simplemente declara.

Si desea reenviar-declarar un puntero, también solo debe declararlo. Para obtener una declaración (una declaración no definitoria) de un objeto, solo debe declararlo con una palabra clave extern.

0

Entiendo exactamente lo que el OP intenta hacer. De hecho, quiero hacer lo mismo. Tras lo que dijo el OP, Tengo el siguiente (en C, C++ no):

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

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

La pregunta es, ¿B.h tienen que incluir A.h? A.h define todo tipo de otras cosas que prefiero no incluir en B.h', so I am hoping is a way to "forward reference" a function pointer, without redefining it in a typedef in B.h` (que probablemente ni siquiera funciona)?

¿O el compilador necesita saber más acerca de f_t en B.h que acerca de, por ejemplo, un referenciado hacia adelante struct?

También es posible que deba replantear el diseño de mi código, pero estoy de acuerdo con el OP en que, en un mundo perfecto, debería haber algún tipo de simetría entre los punteros de función y otros objetos que pueden ser reenviados. referenciado

+1

Puedes usar cualquier puntero de función en lugar del puntero de función real, como 'void (*)()'. El estándar garantiza que los punteros a función de cualquier tipo son convertibles a cualquier otro tipo. – BeeOnRope

Cuestiones relacionadas