A pergunta Onde devo colocar funções que não estão relacionadas a uma classe provocou algum debate sobre se faz sentido em C ++ combinar funções utilitárias em uma classe ou apenas tê-las como funções livres em um espaço para nome.
Eu venho de um background em C # onde a última opção não existe e, portanto, naturalmente tendemos a usar classes estáticas no pequeno código C ++ que escrevo. A resposta mais votada para essa pergunta, bem como vários comentários, dizem que as funções livres devem ser preferidas, mesmo sugerindo que as classes estáticas eram um antipadrão. Por que isso acontece em C ++? Pelo menos na superfície, métodos estáticos em uma classe parecem indistinguíveis de funções livres em um espaço para nome. Por que, portanto, a preferência pelo último?
As coisas seriam diferentes se a coleção de funções utilitárias precisasse de alguns dados compartilhados, por exemplo, um cache que pudesse ser armazenado em um campo estático privado?
fonte
Respostas:
Eu acho que responder que devemos comparar as intenções de ambas as classes e namespaces. De acordo com a Wikipedia:
Classe
Namespace
Agora, o que você está tentando alcançar colocando as funções em uma classe (estaticamente) ou em um espaço para nome? Aposto que a definição de um espaço para nome descreve melhor sua intenção - tudo o que você deseja é um contêiner para suas funções. Você não precisa de nenhum dos recursos descritos na definição de classe. Observe que as primeiras palavras da definição de classe são " Na programação orientada a objetos ", mas não há nada orientado a objetos em uma coleção de funções.
Provavelmente, também existem razões técnicas, mas como alguém vindo de Java e tentando entender a linguagem de múltiplos paradigmas que é C ++, a resposta mais óbvia para mim é: porque não precisamos de OO para conseguir isso.
fonte
Eu seria muito cauteloso em chamar isso de antipadrão. Os espaços para nome são geralmente preferidos, mas como não há modelos de espaço para nome e os espaços para nome não podem ser passados como parâmetros do modelo, o uso de classes com nada além de membros estáticos é bastante comum.
fonte
No dia em que eu precisava fazer uma aula de FORTRAN. Eu conhecia outras línguas imperativas até então, então achei que poderia fazer o FORTRAN sem muito estudo. Quando entreguei minha primeira lição de casa, o professor me devolveu e pediu para refazê-la: ele disse que os programas Pascal escritos na sintaxe FORTRAN não contam como envios válidos.
Problema semelhante está em jogo aqui: o uso de classes estáticas para hospedar funções utilitárias em C ++ é um idioma estrangeiro para C ++.
Como você mencionou na sua pergunta, o uso de classes estáticas para funções utilitárias em C # é uma necessidade: funções independentes simplesmente não são uma opção em C #. A linguagem necessária para desenvolver um padrão para permitir que os programadores definam funções independentes de alguma outra maneira - a saber, dentro das classes de utilidade estática. Este foi um truque de Java tomado palavra por palavra: por exemplo, java.lang.Math e System.Math do .NET são quase isomórficos.
O C ++, no entanto, oferece namespaces, um recurso diferente para atingir o mesmo objetivo e o usa ativamente na implementação de sua biblioteca padrão. Adicionar uma camada extra de classes estáticas não é apenas desnecessário, mas também um pouco contra-intuitivo para leitores sem C # ou Java background. Em certo sentido, você está introduzindo uma "tradução de empréstimo" no idioma para algo que possa ser expresso de forma nativa.
Quando suas funções precisam compartilhar dados, a situação é diferente. Como suas funções não são mais independentes , o padrão Singleton se torna a maneira preferida de atender a esse requisito.
fonte
Talvez você precise perguntar por que deseja uma classe totalmente estática?
A única razão pela qual consigo pensar é que outras linguagens (Java e C #) que são muito 'tudo é uma classe' as exigem. Como essas linguagens não podem criar funções de nível superior, inventaram um truque para mantê-las, e essa era a função membro estática. Eles são um pouco de solução alternativa, mas o C ++ não precisa disso, você pode criar novas funções independentes de nível superior diretamente.
Se você precisar de funções que operam em um item de dados específico, faz sentido agrupá-las em uma classe que contém os dados, mas essas funções deixam de ser funções e passam a ser membros dessa classe que operam nos dados da classe.
Se você tem uma função que não opera em um tipo de dados específico (eu uso a palavra aqui, pois as classes são formas de definir novos tipos de dados), então é realmente um anti-padrão colocá-los em uma classe, por nada além de fins semânticos.
fonte
Em outras palavras, ter uma classe em vez de um espaço para nome não tem vantagens.
Por um lado, você economiza digitando
static
o tempo todo, embora esse seja um benefício menor.O principal benefício é que é a ferramenta menos poderosa para o trabalho. As classes podem ser usadas para criar objetos, elas podem ser usadas como o tipo de variáveis ou como argumentos de modelo. Nenhum desses são os recursos que você deseja para sua coleção de funções. Portanto, é preferível usar uma ferramenta que não tenha esses recursos, para que a classe não possa ser acidentalmente usada indevidamente.
Depois disso, o uso de um espaço para nome também deixa imediatamente claro para qualquer usuário do seu código que essa é uma coleção de funções e não um modelo para a criação de objetos.
fonte
Uma classe totalmente estática fará o trabalho, mas é como dirigir um caminhão de 53 pés até a mercearia para comprar salgadinhos e salsa quando um sedan de quatro portas fará (ou seja, é um exagero). As aulas vêm com uma pequena quantidade de sobrecarga adicional e sua existência pode dar a alguém a impressão de que instanciar uma pode ser uma boa idéia. As funções gratuitas oferecidas pelo C ++ (e C, onde todas as funções são gratuitas) não fazem isso; são apenas funções e nada mais.
Na verdade não. O objetivo original do
static
C (e posterior do C ++) era oferecer armazenamento persistente que pode ser usado em qualquer nível de escopo:Você pode levar o escopo para o nível de um arquivo, o que o torna visível para todos os escopos mais estreitos, mas não fora do arquivo:
Um membro da classe estática privada em C ++ serve ao mesmo propósito, mas está limitado ao escopo de uma classe. A técnica usada no
counter()
exemplo acima também funciona dentro dos métodos C ++ e é algo que eu realmente recomendo fazer se a variável não precisar ser visível para toda a classe.fonte
Se uma função não mantém um estado e é reentrada, parece que não faz muito sentido empurrá-la para dentro de uma classe (a menos que seja forçada pelo idioma). Se a função mantiver algum estado (por exemplo, ela pode ser tornada segura para threads por meio de um mutex estático), os métodos estáticos em uma classe parecem adequados.
fonte
Grande parte do discurso sobre o assunto aqui faz sentido, embora exista algo muito fundamental sobre C ++ que faça
namespaces
eclass
es /struct
s muito diferentes.Classes estáticas (classes em que todos os membros são estáticos e a classe nunca será instanciada) são objetos em si. Eles não são simplesmente um
namespace
para conter funções.A meta-programação de modelos nos permite usar uma classe estática como um objeto em tempo de compilação.
Considere isto:
Para usá-lo, precisamos de funções contidas em uma classe. Um espaço para nome não funcionará aqui. Considerar:
Agora, para usá-lo:
Desde que um novo alocador exponha uma função
allocate
erelease
que seja compatível, é fácil alternar para um novo alocador.Isso não pode ser alcançado com espaços para nome.
Você sempre precisa de funções para fazer parte de uma classe? Não.
O uso de uma classe estática é um anti-padrão? Depende do contexto.
Nesse caso, o que você está tentando alcançar provavelmente será melhor atendido por meio de programação orientada a objetos.
fonte
Como John Carmack disse:
"Às vezes, a implementação elegante é apenas uma função. Não é um método. Não é uma classe. Não é uma estrutura. Apenas uma função."
Eu acho que isso resume tudo. Por que você faria dessa classe uma força, se claramente não é uma classe? C ++ tem o luxo de que você pode realmente usar funções; em Java, tudo é um método. Então você precisa de classes de utilidade, e muitas delas.
fonte