Namespace + funções versus methods estáticos em uma class

Vamos dizer que tenho, ou vou escrever, um conjunto de funções relacionadas. Vamos dizer que eles são relacionados à matemática. Organizacionalmente, eu deveria:

  1. Escreva essas funções e coloque-as no meu namespace MyMath e consulte-as via MyMath::XYZ()
  2. Crie uma class chamada MyMath e torne esses methods estáticos e consulte o mesmo modo MyMath::XYZ()

Por que eu escolheria um sobre o outro como meio de organizar meu software?

Por padrão, use funções de namespace.

Classes são para construir objects, não para replace namespaces.

No código Orientado a Objetos

Scott Meyers escreveu um item inteiro para seu livro Effective C ++ sobre esse tópico, “Preferir funções não-membro não-membro para funções-membro”. Eu encontrei uma referência online a este princípio em um artigo de Herb Sutter: http://www.gotw.ca/gotw/084.htm

O importante é saber que: Em C ++, as funções no mesmo namespace de uma class pertencem à interface dessa class (porque o ADL pesquisará essas funções ao resolver chamadas de function).

As funções de namespaces, a menos que sejam declaradas como “friend”, não têm access aos internos da class, enquanto os methods estáticos têm.

Isso significa, por exemplo, que, ao manter sua turma, se você precisar alterar os aspectos internos de sua turma, precisará procurar efeitos colaterais em todos os seus methods, incluindo os estáticos.

Extensão I

Adicionando código à interface de uma class.

Em C #, você pode adicionar methods a uma class, mesmo se não tiver access a ela. Mas em C ++, isso é impossível.

Mas, ainda em C ++, você ainda pode adicionar uma function namespaced, mesmo para uma class que alguém escreveu para você.

Veja do outro lado, isso é importante ao projetar seu código, porque colocando suas funções em um namespace, você autorizará seus usuários a aumentar / completar a interface da class.

Extensão II

Um efeito colateral do ponto anterior, é impossível declarar methods estáticos em vários headers. Todos os methods devem ser declarados na mesma class.

Para namespaces, funções do mesmo namespace podem ser declaradas em múltiplos headers (a function swap quase-padrão é o melhor exemplo disso).

Extensão III

O cooless básico de um namespace é que em algum código, você pode evitar mencioná-lo, se você usar a palavra-chave “using”:

 #include  #include  // Etc. { using namespace std ; // Now, everything from std is accessible without qualification string s ; // Ok vector v ; // Ok } string ss ; // COMPILATION ERROR vector vv ; // COMPILATION ERROR 

E você pode limitar a “poluição” a uma class:

 #include  #include  { using std::string ; string s ; // Ok vector v ; // COMPILATION ERROR } string ss ; // COMPILATION ERROR vector vv ; // COMPILATION ERROR 

Esse “padrão” é obrigatório para o uso adequado do idioma de troca quase padrão.

E isso é impossível de fazer com methods estáticos em classs.

Portanto, os namespaces do C ++ possuem sua própria semântica.

Mas vai mais longe, já que você pode combinar namespaces de maneira semelhante à inheritance.

Por exemplo, se você tem um namespace A com uma function AAA, um namespace B com uma function BBB, você pode declarar um namespace C e trazer AAA e BBB nesse namespace usando a palavra-chave.

Conclusão

Namespaces são para namespaces. Classes são para classs.

O C ++ foi projetado de forma que cada conceito é diferente e é usado de forma diferente, em diferentes casos, como solução para diferentes problemas.

Não use classs quando precisar de namespaces.

E no seu caso, você precisa de namespaces.

Há muitas pessoas que discordariam de mim, mas é assim que eu vejo:

Uma class é essencialmente uma definição de um certo tipo de object. Os methods estáticos devem definir operações que estão intimamente vinculadas a essa definição de object.

Se você vai ter apenas um grupo de funções relacionadas não associadas a um object subjacente ou a definição de um tipo de object , então eu diria que vá apenas com um namespace. Só para mim, conceitualmente, isso é muito mais sensato.

Por exemplo, no seu caso, pergunte a si mesmo: “O que é um MyMath?” Se o MyMath não definir um tipo de object, então eu diria: não faça disso uma class.

Mas como eu disse, eu sei que há muitas pessoas que (mesmo veementemente) discordam de mim sobre isso (em particular, desenvolvedores Java e C #).

  • Se você precisar de dados estáticos, use methods estáticos.
  • Se forem funções de modelo e você quiser especificar um conjunto de parâmetros de modelo para todas as funções, use methods estáticos em uma class de modelo.

Caso contrário, use funções de namespace.


Em resposta aos comentários: sim, os methods estáticos e os dados estáticos tendem a ser usados ​​em excesso. É por isso que eu ofereci apenas dois cenários relacionados , em que acho que podem ser úteis. No exemplo específico do OP (um conjunto de rotinas matemáticas), se ele quisesse a capacidade de especificar parâmetros – digamos, um tipo de dados de núcleo e precisão de saída – que seria aplicado a todas as rotinas, ele poderia fazer algo como:

 template class MyMath { // routines operate on datatype T, preserving at least decimalPlaces precision }; // math routines for manufacturing calculations typedef MyMath CAMMath; // math routines for on-screen displays typedef MyMath PreviewMath; 

Se você não precisa disso, use um namespace.

Você deve usar um namespace, porque um namespace tem muitas vantagens sobre uma class:

  • Você não precisa definir tudo no mesmo header
  • Você não precisa expor toda a sua implementação no header
  • Você não pode using um membro da turma; você pode using um membro de namespace
  • Você não pode using class , embora using namespace não seja uma boa idéia
  • Usando uma class implica que há algum object a ser criado quando realmente não há nenhum

Membros estáticos são, na minha opinião, muito muito utilizados. Eles não são uma necessidade real na maioria dos casos. As funções de membros estáticos provavelmente são melhores como funções de escopo de arquivo, e os membros de dados estáticos são apenas objects globais com uma reputação melhor e imerecida.

Eu preferiria namespaces, dessa forma você pode ter dados privados em um namespace anônimo no arquivo de implementação (para que ele não tenha que aparecer no header em vez de membros private ). Outro benefício é que, using seu namespace, os clientes dos methods podem optar por não especificar MyMath::

Mais um motivo para usar a class – Opção para usar especificadores de access. Você pode então quebrar seu método estático público em methods privados menores. Método público pode chamar vários methods privados.

O namespace e o método de class têm seus usos. O namespace tem a capacidade de se espalhar pelos arquivos, mas isso é uma fraqueza se você precisar impor todos os códigos relacionados para ir em um arquivo. Como mencionado acima, a class também permite que você crie membros estáticos privados na class. Você pode tê-lo no namespace anônimo do arquivo de implementação, no entanto, ainda é um escopo maior do que tê-los dentro da class.