2009-11-08 10 views
11

¿Cuál es la mejor práctica para C++ Public API?¿Cuál es la mejor práctica para C++ Public API?

Estoy trabajando en un proyecto de C++ que tiene múltiples espacios de nombres, cada uno con múltiples objetos. Algunos objetos tienen los mismos nombres, pero se encuentran en espacios de nombres diferentes. Actualmente, cada objeto tiene su propio archivo .cpp y .h. No estoy seguro de cómo decir esto ... ¿Sería apropiado crear un segundo archivo .h para exponer solo la API pública? ¿Debería ser un archivo .h por espacio de nombres o por objeto o algún otro ámbito? ¿Cuál podría ser una mejor práctica para crear API públicas para bibliotecas C++?

Gracias por cualquier ayuda, Chenz

Respuesta

2

A veces es conveniente tener una única clase en cada par de archivos .cpp y .h y tener la jerarquía del espacio de nombres como la jerarquía del directorio.
Por ejemplo, si usted tiene esta clase:

namespace stuff { 
    namespace important { 
    class SecretPassword 
    { 
     ... 
    }; 
    } 
} 

entonces será en dos archivos:

/stuff/important/SecretPassword.cpp 
/stuff/important/SecretPassword.h 

otra posible disposición podría ser:

/src/stuff/important/SecretPassword.cpp 
/include/stuff/important/SecretPassword.h 
+0

Pero al juntar todo en una sola biblioteca .so, ¿distribuyo una estructura de directorios de inclusión profunda? Chenz –

+0

Quiero decir .so o .dll –

+0

@Crazy Chenz, sí, esta es una posibilidad. Así es como se hace en el kernel de Linux, por ejemplo, y también en algún grado de impulso. – shoosh

1

Yo diría que es mejor decidió por usted, y el tipo de 'biblioteca' que es esto.

¿Su API proporciona una "Acción"? ¿o maneja solo un "tipo de datos" abstracto? ejemplos para esto serían zlib y libpng. Ambos tienen solo un encabezado que proporciona todo lo que se necesita para realizar para qué son las bibliotecas.

Si su biblioteca es una colección de clases no relacionadas (o incluso relacionadas) que tienen, o no, el mismo objetivo, proporcione cada subconjunto con su propio encabezado. El mayor ejemplo de esto será el impulso.

0

gran respuesta LiraNuna.

¿Está proporcionando una API para una aplicación o una biblioteca?

Una API de aplicaciones generalmente solo proporcionará métodos que consulten el estado de una aplicación o intenten alterar ese estado. En este caso, generalmente tendría declaraciones de interfaz separadas en un archivo de encabezado separado. Sus objetos implementarían esta interfaz para manejar las solicitudes API.

Una biblioteca generalmente expone objetos que se pueden reutilizar. En este caso, en general, su API es simplemente los métodos públicos en el archivo de encabezado.

+0

"Gran respuesta LiraNuna". Entonces, votala? :( – LiraNuna

+0

Haha Generalmente respondo y luego voto;) – Josh

+0

Tengo una biblioteca principal que debería ser reutilizable, y luego algunos espacios de nombres que contienen todos los objetos y ayudantes para las aplicaciones que usan el núcleo. El núcleo es para lo que quiero "exponer" una API pública. –

2

día G,

Una sugerencia es tomar un vistazo a lenguaje C++ de Handle-cuerpo, a veces conocido como gato de Cheshire. Aquí está James Coplien's original paper que contiene la expresión idiomática.

Este es un método bien conocido para desacoplar las API públicas de las implementaciones.

HTH

+3

Otro nombre para este modismo (que creo que se ha vuelto más popular, pero podría estar equivocado) es el "modismo pimpl" - indicador de implementación. –

+0

@michael, tienes razón. ese nombre también ha sido agregado pero bastante recientemente iirc. handle/body fue el nombre original que Cope le dio en su libro de 1991 "Estilos y modismos avanzados de programación en C++"

1

Aquí es lo que estoy acostumbrado a hacer:

"Algunos objetos tienen los mismos nombres, pero están en diferentes espacios de nombres"

Es por eso que existen espacios de nombres.

"¿Sería apropiado para crear un segundo archivo .h para exponer sólo el API pública?"

Siempre debe exponer sólo el API pública. Pero, ¿qué significa exponer la API pública? Si fuera solo a los encabezados, dado que la API pública depende de la API privada, la API pública sería incluida por la API pública de todos modos. Exponer una API pública marca funciones/clases públicas con una macro (que en el caso de Windows exporta funciones públicas a la tabla de símbolos, y probablemente pronto será adoptada por los sistemas Unix). Por lo tanto, debe definir una macro como MYLIB_API o MYLIB_DECLSPEC, simplemente verifique algunas bibliotecas existentes y la documentación de MS declspec. Es suficiente, generalmente API no pública se mantendrá en subdirectorios por lo que no atiende al usuario de la biblioteca.

"¿Debería ser un archivo .h por espacio de nombres o por objeto o algún otro ámbito?"

Prefiero el estilo Java, uno público clase por encabezado. Descubrí que las libs escritas de esta manera son mucho más limpias y legibles que las que mezclan nombres de archivos y estructuras. Pero hay casos en que freno esta regla, especialmente cuando se trata de plantillas. En tales casos, doy un mensaje de advertencia para que no incluya el encabezado directamente y explico cuidadosamente en los comentarios lo que está sucediendo.

+0

"Pero, ¿qué significa exponer API pública?" Estaba pensando en la reproducción de todos los encabezados para su distribución sin sus métodos privados y vars. –

+0

Quiero decir ... sin sus prototipos de métodos privados y declaraciones de variables privadas. –

+0

Eso no tiene sentido IMO. De hecho, esto haría que tu biblioteca sea más difícil de entender y mantener. Si alguien tiene que extender su clase, entonces probablemente le gustaría ver toda la estructura de clase y no solo miembros públicos y protegidos. La definición de clase debe mantenerse definitivamente en un encabezado. – doc

0

Estoy de acuerdo con lo que dijo el DOC - una clase por archivo. 99.9% del tiempo!

Además, considere qué nombre de archivo usar. En general, es una mala idea tener múltiples encabezados del mismo nombre en directorios diferentes, a pesar de que las clases que contienen pueden estar en diferentes espacios de nombres.

Especialmente si se trata de una API pública, probablemente no pueda controlar qué rutas de acceso incluyen las definidas por el usuario de su biblioteca, por lo que una compilación puede encontrar la incorrecta. Ajustar el orden de las rutas include definitivamente sería no ¡sería una solución que recomendaría!

Utilizamos una convención de nomenclatura de Namespace-Class.h para identificar explícitamente las clases en los archivos.

+0

¿Puedo preguntar qué haces con espacios de nombres largos? Digamos que tienes una clase mylib :: graphics :: formats :: JpegLoader. Nombre del encabezado Mylib_Graphics_Formats-JpegLoader.h? Es algo frustrante usar tales encabezados. IMO, la mejor manera de evitar inclusiones accidentales es forzar que su nombre de biblioteca sea parte de la ruta de inclusión; en nuestro ejemplo, la inclusión sería similar a #include . Hasta que tengas "mylib" en <> todo estará bien. – doc

+0

Afortunadamente, nuestros espacios de nombres no están anidados tan profundo; solo un espacio de nombre, raramente 2, así que no está mal. ¿De qué manera es frustrante? ¿Y cuál es la diferencia entre '#include" Mylib-Graphics-Formats-JpegLoader.h "' o '#include" mylib/graphics/formats/JpegLoader.h "'? ¿Todavía tiene que escribir la 'ruta' completa de alguna manera? –

+0

Puede tener #include si mantiene la estructura del directorio con respecto a los espacios de nombres, y por mi parte sería . Si mantiene todo en un directorio, entonces OK. – doc

Cuestiones relacionadas