entiendo que una biblioteca de C++ debe utilizar un espacio de nombres para evitar conflictos de nombres, pero como ya tengo a:¿El uso de un espacio de nombres C++ aumenta el acoplamiento?
#include
la cabecera correcta (o hacia adelante declare las clases que tengo la intención de usar)- utilizar esas clases por su nombre
no hace estas dos parámetros inferir la misma información transmitida por un espacio de nombres. El uso de un espacio de nombres ahora introduce un tercer parámetro: el nombre completo. Si la implementación de la biblioteca cambia, ahora hay tres posibles cosas que necesito cambiar. ¿No es esto, por definición, un aumento en el acoplamiento entre el código de la biblioteca y mi código?
Por ejemplo, mira a Xerces-C: Se define una interfaz pura virtual llamado Parser
dentro del espacio de nombres XERCES_CPP_NAMESPACE
. Puedo hacer uso de la interfaz Parser
en mi código al incluir el archivo de encabezado apropiado y luego importar el espacio de nombres using namespace XERCES_CPP_NAMESPACE
o prologar declaraciones/definiciones con XERCES_CPP_NAMESPACE::
.
A medida que el código evoluciona, quizás haya una necesidad de soltar Xerces a favor de un analizador diferente. Estoy parcialmente "protegido" del cambio en la implementación de la biblioteca por la interfaz pura-virtual (más aún si uso una fábrica para construir mi analizador), pero tan pronto como cambie de Xerces a otra cosa, necesito peine a través de mi código y cambie todos mis códigos using namespace XERCES_CPP_NAMESPACE
y XERCES_CPP_NAMESPACE::Parser
.
me encontré con esto recientemente cuando refactorizado un proyecto existente C++ para dividir-cabo algunas funciones útiles existentes en una biblioteca:
foo.h
class Useful; // Forward Declaration
class Foo
{
public:
Foo(const Useful& u);
...snip...
}
foo. cpp
#include "foo.h"
#include "useful.h" // Useful Library
Foo::Foo(const Useful& u)
{
... snip ...
}
En gran parte por ignorancia (y parcialmente por holgazanería) en ese momento, toda la funcionalidad de useful.lib
se colocó en el espacio de nombres global.
Como el contenido de useful.lib
crecieron (y más clientes comenzaron a utilizar la funcionalidad), se decidió a mover todo el código de useful.lib
en su propio espacio de nombres llamado "useful"
.
Los archivos del cliente .cpp
fueron fáciles de solucionar, simplemente agregue un using namespace useful
;
foo.cpp
#include "foo.h"
#include "useful.h" // Useful Library
using namespace useful;
Foo::Foo(const Useful& u)
{
... snip ...
}
pero los archivos .h
eran realmente mano de obra intensiva.En lugar de contaminar el espacio de nombres global poniendo using namespace useful;
en los archivos de cabecera, envolví las declaraciones existentes hacia adelante en el espacio de nombres:
foo.h
namespace useful {
class Useful; // Forward Declaration
}
class Foo
{
public:
Foo(const useful::Useful& u);
...snip...
}
había docenas y docenas () de archivos y esto terminó siendo un gran dolor! No debería haber sido tan difícil. Claramente, hice algo mal con el diseño o la implementación.
Aunque sé que el código de la biblioteca debería estar en su propio espacio de nombres, ¿habría sido ventajoso para el código de la biblioteca permanezca en el espacio de nombres global, y en lugar de tratar de gestionar el #includes
?
"(b) Detalles de implementación inferidos por el espacio de nombres" - ¿Puede explicar esto con más detalle? No entiendo lo que eso significa. –
Casi me quedé dormido antes de llegar a la pregunta, y todavía no entiendo por qué preguntas. ¿Consideraste que: utilizaste útil? Útil; –
Eso es mucho texto. ¿Hay alguna versión condensada que pueda leer? – wheaties