Provavelmente uma duplicata, mas não é fácil de pesquisar ...
Dado um cabeçalho como:
namespace ns1
{
class MyClass
{
void method();
};
}
Eu vi method()
definido de várias maneiras no arquivo .cpp:
Versão 1:
namespace ns1
{
void MyClass::method()
{
...
}
}
Versão 2:
using namespace ns1;
void MyClass::method()
{
...
}
Versão 3:
void ns1::MyClass::method()
{
...
}
Existe uma maneira 'certa' de fazer isso? Alguma dessas coisas está "errada" no sentido de que não significam a mesma coisa?
c++
coding-style
namespaces
Senhor menino
fonte
fonte
Respostas:
A versão 2 não é clara e fácil de entender porque você não sabe a qual namespace
MyClass
pertence e é simplesmente ilógica (a função de classe não está no mesmo namespace?)A versão 1 está certa porque mostra que, no namespace, você está definindo a função.
A versão 3 também está certa porque você usou o
::
operador de resolução de escopo para se referir aoMyClass::method ()
no namespacens1
. Eu prefiro a versão 3.Consulte Namespaces (C ++) . Esta é a melhor maneira de fazer isso.
fonte
namespace N {struct X { void f(); }; X operator==( X const &, X const & ); }
, agora no arquivo cpp com a instrução using você pode definir a função de membro comovoid X::f() {}
, mas se você definirX operator==(X const&, X const&)
você estará definindo um operador diferente daquele definido no cabeçalho (você terá que usar 1 ou 3 para a função gratuita lá).5 anos depois e pensei em mencionar isso, que parece bom e não é mau
fonte
Estou usando a versão 4 (abaixo) porque combina a maioria das vantagens da versão 1 (concisão da definição resoetiva) e da versão 3 (ser explícito ao máximo). A principal desvantagem é que as pessoas não estão acostumadas, mas como eu o considero tecnicamente superior às alternativas, não me importo.
Versão 4: use qualificação completa usando aliases de namespace:
No meu mundo, estou freqüentemente usando aliases de namespace, pois tudo é explicitamente qualificado - a menos que não possa (por exemplo, nomes de variáveis) ou seja um ponto de personalização conhecido (por exemplo, swap () em um modelo de função).
fonte
outer
einner
já estão definidos como namespaces em outros arquivos de cabeçalho?A versão 3 torna a associação entre a classe e o namespace muito explícita à custa de mais digitação. A versão 1 evita isso, mas captura a associação com um bloco. A versão 2 tende a esconder isso, então eu evito aquela.
fonte
Guia de estilo C ++ do Google determina sua versão 1, porém sem indentação.
fonte
Eu escolho Num.3 (também conhecido como a versão detalhada). É mais digitação, mas a intenção é exata para você e para o compilador. O problema que você postou no estado em que se encontra é, na verdade, mais simples do que o mundo real. No mundo real, existem outros escopos de definições, não apenas os membros da classe. Suas definições não são muito complicadas apenas com classes - porque seu escopo nunca é reaberto (ao contrário de namespaces, escopo global, etc.).
Num.1 isso pode falhar com escopos diferentes de classes - qualquer coisa que possa ser reaberta. Portanto, você pode declarar uma nova função em um namespace usando essa abordagem, ou seus inlines podem acabar sendo substituídos via ODR. Você precisará disso para algumas definições (notadamente, especializações de modelo).
Num.2 Isso é muito frágil, particularmente em grandes bases de código - conforme os cabeçalhos e dependências mudam, seu programa irá falhar ao compilar.
Num.3 Isso é ideal, mas muito para digitar - qual sua intenção é definir algo . Isso faz exatamente isso, e o compilador entra em ação para garantir que você não cometeu um erro, uma definição não está fora de sincronia com sua declaração, etc.
fonte
Acontece que não é apenas uma "questão de estilo de codificação". Num. 2 leva a um erro de vinculação ao definir e inicializar uma variável declarada externa no arquivo de cabeçalho. Dê uma olhada no exemplo na minha pergunta. Definição de constante dentro do namespace no arquivo cpp
fonte
Todos os caminhos são corretos e cada um tem suas vantagens e desvantagens.
Na versão 1, você tem a vantagem de não precisar escrever o namespace na frente de cada função. A desvantagem é que você obterá uma identificação enfadonha, especialmente se tiver mais de um nível de namespaces.
Na versão 2, você deixa seu código mais limpo, mas se tiver mais de um namespace sendo implementado no CPP, um pode acessar as funções e variáveis do outro diretamente, tornando seu namespace inútil (para aquele arquivo cpp).
Na versão 3, você terá que digitar mais e suas linhas de função podem ser maiores do que a tela, o que é ruim para efeitos de design.
Há também outra maneira como algumas pessoas o usam. É semelhante à primeira versão, mas sem os problemas de identificação.
É tipo isso:
Cabe a você escolher qual é o melhor para cada situação =]
fonte
#ifdef
cláusula.#define OPEN_NS(X)
, acho que é um pouco útil, mas não realmente ... Eu não me oponho a macros, mas isso parece um pouco OTT. Acho que a abordagem de Dietmar Kühl é melhor para namespaces aninhados.