Pergunta

Eu venho de uma experiência em Java, onde pacotes são usados, não namespaces.Estou acostumado a colocar classes que funcionam juntas para formar um objeto completo em pacotes e depois reutilizá-las posteriormente a partir desse pacote.Mas agora estou trabalhando em C++.

Como você usa namespaces em C++?Você cria um único namespace para todo o aplicativo ou cria namespaces para os componentes principais?Se sim, como você cria objetos a partir de classes em outros namespaces?

Foi útil?

Solução

Namespaces são essencialmente pacotes.Eles podem ser usados ​​assim:

namespace MyNamespace
{
  class MyClass
  {
  };
}

Então no código:

MyNamespace::MyClass* pClass = new MyNamespace::MyClass();

Espero que ajude.

Ou, se quiser sempre usar um namespace específico, você pode fazer o seguinte:

using namespace MyNamespace;

MyClass* pClass = new MyClass();

Editar: Seguindo o que Bernhardrusch disse, eu tendo a não usar a sintaxe "usando namespace x", geralmente especifico explicitamente o namespace ao instanciar meus objetos (ou seja,o primeiro exemplo que mostrei).

E como você pediu abaixo, você pode usar quantos namespaces desejar.

Outras dicas

Para evitar dizer tudo, Mark Ingram já deu uma pequena dica para usar namespaces:

Evite a diretiva "usando namespace" em arquivos de cabeçalho - isso abre o namespace para todas as partes do programa que importam esse arquivo de cabeçalho.Em arquivos de implementação (*.cpp) isso normalmente não é um grande problema - embora eu prefira usar a diretiva "using namespace" no nível da função.

Acho que os namespaces são usados ​​principalmente para evitar conflitos de nomenclatura - não necessariamente para organizar sua estrutura de código.Eu organizaria programas C++ principalmente com arquivos de cabeçalho/estrutura de arquivos.

Às vezes, namespaces são usados ​​em projetos C++ maiores para ocultar detalhes de implementação.

Nota adicional à diretiva using:Algumas pessoas preferem usar "using" apenas para elementos únicos:

using std::cout;  
using std::endl;

Vincent Robert está certo em seu comentário Como você usa namespaces corretamente em C++?.

Usando espaço para nome

Namespaces são usados ​​no mínimo para ajudar a evitar colisão de nomes.Em Java, isso é aplicado através do idioma "org.domain" (porque supõe-se que ninguém usará nada além de seu próprio nome de domínio).

Em C++, você pode atribuir um namespace a todo o código do seu módulo.Por exemplo, para um módulo MyModule.dll, você pode atribuir ao seu código o namespace MyModule.Já vi em outro lugar alguém usando MyCompany::MyProject::MyModule.Acho que isso é um exagero, mas, no geral, parece-me correto.

Usando "usando"

Using deve ser usado com muito cuidado porque importa efetivamente um (ou todos) símbolos de um namespace para o seu namespace atual.

É ruim fazer isso em um arquivo de cabeçalho porque seu cabeçalho poluirá todas as fontes, incluindo-o (isso me lembra macros ...), e mesmo em um arquivo de origem, estilo ruim fora do escopo de uma função, porque será importado no escopo global os símbolos do namespace.

A maneira mais segura de usar "using" é importar símbolos selecionados:

void doSomething()
{
   using std::string ; // string is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   std::cout << a << std::endl ;
}

void doSomethingElse()
{
   using namespace std ; // everything from std is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   cout << a << endl ;
}

Você verá muito "usando o namespace std"; nos códigos de tutorial ou exemplo.O motivo é reduzir o número de símbolos para facilitar a leitura, não porque seja uma boa ideia.

"Usando namespace std;" é desencorajado por Scott Meyers (não me lembro exatamente de qual livro, mas posso encontrá -lo, se necessário).

Composição do namespace

Namespaces são mais do que pacotes.Outro exemplo pode ser encontrado em "The C++ Programming Language" de Bjarne Stroustrup.

Na "Edição Especial", em 8.2.8 Composição do Namespace, ele descreve como você pode mesclar dois namespaces AAA e BBB em outro chamado CCC.Assim, CCC se torna um apelido para AAA e BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

Você pode até importar símbolos selecionados de diferentes namespaces para criar sua própria interface de namespace personalizada.Ainda não encontrei um uso prático para isso, mas, em teoria, é legal.

Não vi nenhuma menção a isso nas outras respostas, então aqui estão meus 2 centavos canadenses:

No tópico "usando namespace", uma instrução útil é o alias do namespace, permitindo "renomear" um namespace, normalmente para dar-lhe um nome mais curto.Por exemplo, em vez de:

Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::TheClassName foo;
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::AnotherClassName bar;

você pode escrever:

namespace Shorter = Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally;
Shorter::TheClassName foo;
Shorter::AnotherClassName bar;

Não dê ouvidos a todas as pessoas dizendo que namespaces são apenas namespaces.

Eles são importantes porque são considerados pelo compilador como aplicadores do princípio da interface.Basicamente, isso pode ser explicado com um exemplo:

namespace ns {

class A
{
};

void print(A a)
{
}

}

Se você quisesse imprimir um objeto A, o código seria este:

ns::A a;
print(a);

Observe que não mencionamos explicitamente o namespace ao chamar a função.Este é o princípio da interface:C++ considera uma função que toma um tipo como argumento como parte da interface desse tipo, portanto, não há necessidade de especificar o namespace porque o parâmetro já implicava o namespace.

Agora, por que esse princípio é importante?Imagine que o autor da classe A não forneceu uma função print() para esta classe.Você mesmo terá que fornecer um.Como você é um bom programador, você definirá esta função em seu próprio namespace, ou talvez no namespace global.

namespace ns {

class A
{
};

}

void print(A a)
{
}

E seu código pode começar a chamar a função print(a) onde você quiser.Agora imagine que anos depois, o autor decida fornecer uma função print(), melhor que a sua porque ele conhece o funcionamento interno de sua classe e pode fazer uma versão melhor que a sua.

Então os autores de C++ decidiram que sua versão da função print() deveria ser usada em vez daquela fornecida em outro namespace, para respeitar o princípio da interface.E que esse “upgrade” da função print() deve ser o mais fácil possível, o que significa que você não terá que alterar todas as chamadas para a função print().É por isso que "funções de interface" (funções no mesmo namespace de uma classe) podem ser chamadas sem especificar o namespace em C++.

E é por isso que você deve considerar um namespace C++ como uma "interface" ao usá-lo e ter em mente o princípio da interface.

Se você quiser uma explicação melhor sobre esse comportamento, consulte o livro C++ excepcional de Herb Sutter

Projetos C++ maiores que vi dificilmente usavam mais de um namespace (por exemplo,aumentar a biblioteca).

Na verdade, o boost usa vários namespaces, normalmente cada parte do boost tem seu próprio namespace para o funcionamento interno e então pode colocar apenas a interface pública no namespace de nível superior.

Pessoalmente, acho que quanto maior se torna uma base de código, mais importantes se tornam os namespaces, mesmo dentro de um único aplicativo (ou biblioteca).No trabalho, colocamos cada módulo da nossa aplicação em seu próprio namespace.

Outro uso (sem trocadilhos) de namespaces que uso muito é o namespace anônimo:

namespace {
  const int CONSTANT = 42;
}

Isso é basicamente o mesmo que:

static const int CONSTANT = 42;

Usar um namespace anônimo (em vez de estático) é, no entanto, a maneira recomendada para que o código e os dados sejam visíveis apenas na unidade de compilação atual em C++.

Além disso, observe que você pode adicionar a um namespace.Isso fica mais claro com um exemplo, o que quero dizer é que você pode ter:

namespace MyNamespace
{
    double square(double x) { return x * x; }
}

em um arquivo square.h, e

namespace MyNamespace
{
    double cube(double x) { return x * x * x; }
}

em um arquivo cube.h.Isso define um único namespace MyNamespace (ou seja, você pode definir um único namespace em vários arquivos).

Em Java:

package somepackage;
class SomeClass {}

Em C++:

namespace somenamespace {
    class SomeClass {}
}

E usando-os, Java:

import somepackage;

E C++:

using namespace somenamespace;

Além disso, os nomes completos são "somepackge.SomeClass" para Java e "somenamespace::SomeClass" para C++.Usando essas convenções, você pode organizar como está acostumado em Java, incluindo criar nomes de pastas correspondentes para namespaces.Os requisitos de pasta->pacote e arquivo->classe não estão lá, então você pode nomear suas pastas e classes independentemente de pacotes e namespaces.

Você também pode conter "using namespace ..." dentro de uma função, por exemplo:

void test(const std::string& s) {
    using namespace std;
    cout << s;
}

@Marius

Sim, você pode usar vários namespaces ao mesmo tempo, por exemplo:

using namespace boost;   
using namespace std;  

shared_ptr<int> p(new int(1));   // shared_ptr belongs to boost   
cout << "cout belongs to std::" << endl;   // cout and endl are in std

[fevereiro2014 -- (Já faz tanto tempo assim?):Este exemplo específico agora é ambíguo, como Joey aponta abaixo.Impulso e padrão::agora cada um tem um shared_ptr.]

De modo geral, eu crio um namespace para um corpo de código se acreditar que pode haver conflitos de função ou nome de tipo com outras bibliotecas.Também ajuda o código da marca, ala impulsionar:: .

Prefiro usar um namespace de nível superior para o aplicativo e subnamespaces para os componentes.

A maneira como você pode usar classes de outros namespaces é surpreendentemente muito semelhante à maneira em java.Você pode usar "use NAMESPACE", que é semelhante a uma instrução "import PACKAGE", por exemplo.usar padrão.Ou você especifica o pacote como prefixo da classe separado por "::", por exemplo.std::string.Isso é semelhante a "java.lang.String" em Java.

Observe que um namespace em C++ é realmente apenas um namespace.Eles não fornecem nenhum encapsulamento que os pacotes fazem em Java, então você provavelmente não os usará tanto.

Usei namespaces C++ da mesma forma que faço em C#, Perl, etc.É apenas uma separação semântica de símbolos entre material de biblioteca padrão, material de terceiros e meu próprio código.Eu colocaria meu próprio aplicativo em um namespace e, em seguida, um componente de biblioteca reutilizável em outro namespace para separação.

Outra diferença entre Java e C++ é que em C++, a hierarquia do namespace não precisa ajustar o layout do sistema de arquivos.Portanto, tendo a colocar uma biblioteca reutilizável inteira em um único namespace e os subsistemas da biblioteca em subdiretórios:

#include "lib/module1.h"
#include "lib/module2.h"

lib::class1 *v = new lib::class1();

Eu só colocaria os subsistemas em namespaces aninhados se houvesse a possibilidade de conflito de nomes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top