2012-01-25 16 views
6

Esta es una versión completamente reescrita de an earlier question; Creo que la primera versión omitió detalles importantes; este proporciona todo el contexto.C/C++ puzzle API

Tengo un encabezado de alguna API de C++. La API declara algunas clases de esta manera:

class Foo 
{ 
public: 
    inline void Bar(void); 
    /* more inlines */ 
private: 
    inline Foo(); 
    /* maybe more inline constructors */ 
} 

es decir, no miembros, todas las funciones son en línea y públicas, excepto constructores. Los constructores son privados, por lo que entiendo C++, realmente no puedo llamarlos. Para crear estos objetos se supone que debo utilizar auto_ptr s a ellos:

class FooAutoPtr : public std::auto_ptr<Foo> 
{ 
public: 
    inline FooAutoPtr(); 
    /* one for each Foo constructors */ 
} 

La API también tiene un segundo conjunto de funciones de la siguiente manera:

void Foo_Bar(void *self); 
Foo* Foo_Constructor(); 

Llamémosles funciones básicas, porque estos son los símbolos realmente exportados desde la aplicación de host. No las clases de C++.

Las funciones principales tienen una vinculación C (es decir, declararon como extern "C"), pero se declaran como tomar y devolver tipos C++ (por ejemplo, pueden tomar una referencia: Foo &foo). Finalmente, el encabezado contiene la implementación de las funciones en línea de las clases de C++. Todas estas funciones hacen lo mismo: llaman a las funciones básicas. Por ejemplo, el FooAutoPtr constructor es así:

inline FooAutoPtr::FooAutoPtr() 
{ 
    reset(Foo_Constructor()); 
} 

Por lo que entiendo, el código recibe algún objeto que se supone que es un puntero a Foo desde la aplicación host y cambia el aparatito auto_ptr señalar a este objeto . Pero para el desarrollador, parece que fue un verdadero puntero al Foo. Y llamando Foo::Bar() es la siguiente:

inline Foo::Bar() 
{ 
    Foo_Bar(this); 
} 

Esto vale para todas las clases y los métodos de C++. Inteligente, ¿eh?

Ahora, ¿alguien podría explicar qué significa todo esto? :) No es una verdadera API de C++, ¿o sí? Para mí, parece más un envoltorio delgado de C++ sobre una API de C. Si es así, ¿puedo redeclarar las funciones básicas para perder los bits de C++? Entiendo cómo escribir un contenedor C en C++ (en realidad, ya lo escribí), pero, si es posible, prefiero perder el contenedor y usar las funciones directamente. ¿Pero cómo pierdo las cosas de C++?

Por ejemplo, podría haber una función con las referencias:

Bar& Foo_GetBar(void* self, const Baz& baz, int& i); 

Ahora mismo llamarlo desde mi C++ envoltura de la siguiente manera:

typedef struct bar bar_t; /* and others */ 
/*...*/ 
bar_t* 
foo_get_bar(foo_t* foo, baz_t* baz, int* i) 
{ 
    return (bar_t*) &Foo_GetBar(foo, *(Baz*)baz, *i); 
} 

y funciona (no tengo ni idea, cómo). Pero prefiero que se vuelve a declarar como esto:

/* type? */ Foo_GetBar(foo_t*, /* type? /*, /* type? */); 

ACTUALIZACIÓN: He encontrado una cosa interesante que confirma Neil's answer. Es código en Common Lisp que usa la misma API. (Naturalmente, tiene que usar la parte C). Y, por lo que puedo (apenas) leer en la fuente, el autor simplemente usó punteros en lugar de referencias.He aquí un fragmento de código que convierte el C++ declaraciones a Lisp:

;; use * instead of & - we're not interested in C++ details 
line (regex-replace-all "&" line "*") 

Así que eso es todo :) Gracias a todos!

+8

Wow, una pregunta que _legitimately_ etiquetó tanto 'c' como' C++ '. Una apariencia rara ... – ildjarn

+2

Si las funciones básicas devuelven tipos C++ (referencias), entonces es una API C++ real (_not_ una API C), pero simplemente no es orientada a objetos. –

+0

@SethCarnegie Así que eso es :) Ya ves, el encabezado incluso tiene un comentario cerca de las funciones básicas que dicen que son "para el entorno C-only". Bueno, otro comentario obsoleto :) –

Respuesta

4

En teoría, los detalles de cómo trata un compilador una referencia en una declaración de vinculación C son detalles de implementación no especificados. Sin embargo, muchos compiladores lo tratan como si fuera un puntero. Entonces, si el encabezado de la biblioteca de C++ importa Bar& Foo_GetBar(void* self, const Baz& baz, int& i);, entonces podría intentar importarlo en su encabezado C como bar_t* Foo_GetBar(foo_t* self, const baz_t* baz, int* i); y podría funcionar.

+0

Lo intentaré. Sospechaba algo así, pero no era demasiado valiente para comenzar sin una confirmación :) ¡Gracias! –

+0

Por cierto, actualicé la publicación sobre el código Lisp que acabo de encontrar que utiliza la misma API y sí, simplemente usa punteros :) Así que tienes razón. –

1
#define & * // convert references into pointers. 

Detener. Derecha. Ahí. Eso era una broma, en lugar de un intento de ver cuántos votos acumulados podían acumularse en una sola respuesta.

Pero el enfoque de volver a escribir el archivo de encabezado para reemplazar las referencias con punteros debería funcionar. Debido a que estas son funciones C, no hay ningún problema para preocuparse, y aún no he visto un compilador que no implemente referencias como punteros. (¿Hay alguna otra manera posible?)

+0

'# define' solo funciona para los identificadores, por lo que no puedes hacer ese truco :) –

+0

@Seth: De hecho. Lo cual está bien, de verdad. – Roddy