Sim. Nos velhos tempos, chamamos isso de "função". Vocês crianças hoje com seus "namespaces" malucos. Ei, saia do meu gramado! <shakes fist>
Vagrant
7
@ Uma função dentro de um namespace ainda é uma função. Uma função que pertence a uma classe é chamada de método. Se for um método estático, você o chamará da mesma forma como se fosse uma função dentro de um espaço para nome.
48
5 anos depois e agora estou do lado do @Vagrant. Que pergunta boba!
andrewrk
16
9 anos depois e agora eu tenho a minha própria linguagem de programação que não tem sequer classes: ziglang.org
andrewrk
1
Classes de contêineres do IMO (com apenas métodos estáticos) são úteis em certos casos.
AarCee 17/05/19
Respostas:
272
Se você está procurando uma maneira de aplicar a palavra-chave "estática" a uma classe, como é possível em C #, por exemplo, não será possível sem usar o C ++ gerenciado.
Mas, pela aparência do seu exemplo, você só precisa criar um método estático público no seu objeto BitParser. Igual a:
BitParser.h
classBitParser{public:staticbool getBitAt(int buffer,int bitIndex);// ...lots of great stuffprivate:// Disallow creating an instance of this objectBitParser(){}};
BitParser.cpp
boolBitParser::getBitAt(int buffer,int bitIndex){bool isBitSet =false;// .. determine if bit is setreturn isBitSet;}
Você pode usar esse código para chamar o método da mesma maneira que seu código de exemplo.
JO, você tem um erro de sintaxe . A palavra-chave estática deve ser usada apenas na definição de classe, e não na definição de método.
andrewrk
90
Para deixar sua intenção clara nessa abordagem, você pode usar adicionalmente um construtor privado. private: BitParser() {}Isso impedirá que alguém crie instâncias.
Danvil 22/07/10
7
A segurança do encadeamento @MoatazElmasry é um problema quando você compartilha o estado. Na implementação acima não é compartilhado nenhum estado, de modo que não pode haver qualquer problema com a segurança do thread ... a menos que você está suficientemente estúpido para usar estática dentro essas funções. Então, sim, o código acima é seguro para threads, apenas mantenha o estado persistente fora de suas funções e você estará bem.
JO.
@MoatazElmasry Incorrect. Dois segmentos não podem modificar variáveis locais não estáticas em uma função estática.
JO.
12
Se C ++ 11, eu diria que é melhor BitParser() = delete;transmitir adequadamente a intenção de remover o construtor (não apenas ocultando-o como private).
Mas você deve se lembrar que "classes estáticas" são hacks no tipo de linguagem Java (por exemplo, C #) que são incapazes de ter funções não pertencentes a membros; portanto, eles precisam movê-las dentro das classes como métodos estáticos.
No C ++, o que você realmente deseja é uma função que não seja membro que você declarará em um espaço para nome:
No C ++, o espaço para nome é mais poderoso que as classes para o padrão "método estático Java", porque:
métodos estáticos têm acesso aos símbolos particulares das classes
métodos estáticos privados ainda são visíveis (se inacessíveis) para todos, o que viola um pouco o encapsulamento
métodos estáticos não podem ser declarados para a frente
métodos estáticos não podem ser sobrecarregados pelo usuário da classe sem modificar o cabeçalho da biblioteca
não há nada que possa ser feito por um método estático que não possa ser melhor do que uma função não membro (possivelmente amigo) no mesmo espaço de nome
os espaços para nome têm sua própria semântica (eles podem ser combinados, podem ser anônimos etc.)
etc.
Conclusão: Não copie / cole esse padrão Java / C # em C ++. Em Java / C #, o padrão é obrigatório. Mas em C ++, é um estilo ruim.
Edit 2010-06-10
Houve um argumento a favor do método estático porque, às vezes, é necessário usar uma variável de membro privado estático.
Primeiro, myGlobal é chamado myGlobal porque ainda é uma variável privada global. Uma olhada na fonte do CPP esclarecerá que:
// CPP
std::string Foo::myGlobal ;// You MUST declare it in a CPPvoidFoo::barA(){// I can access Foo::myGlobal}voidFoo::barB(){// I can access Foo::myGlobal, too}void barC(){// I CAN'T access Foo::myGlobal !!!}
À primeira vista, o fato de a função livre barC não poder acessar Foo :: myGlobal parece uma coisa boa do ponto de vista do encapsulamento ... É legal porque alguém olhando para o HPP não poderá (a menos que recorra à sabotagem) acessar Foo :: myGlobal.
Mas se você olhar atentamente, verá que é um erro colossal: não apenas sua variável privada ainda deve ser declarada no HPP (e, portanto, visível para todo o mundo, apesar de ser privado), mas você deve declarar no mesmo HPP todas as funções (como em TODAS) que serão autorizadas a acessá-lo !!!
Portanto, usar um membro estático privado é como andar nu, com a lista de seus amantes tatuados na pele: ninguém está autorizado a tocar, mas todos podem espiar. E o bônus: todos podem ter o nome daqueles autorizados a jogar com suas privadas.
private de fato ... :-D
A solução "namespaces anônimos"
Os namespaces anônimos terão a vantagem de tornar as coisas privadas realmente privadas.
Primeiro, o cabeçalho HPP
// HPPnamespaceFoo{void barA();}
Apenas para ter certeza de que você observou: Não há declaração inútil de barB nem myGlobal. O que significa que ninguém lendo o cabeçalho sabe o que está escondido atrás da barraA.
Então, o CPP:
// CPPnamespaceFoo{namespace{
std::string myGlobal ;voidFoo::barB(){// I can access Foo::myGlobal}}void barA(){// I can access myGlobal, too}}void barC(){// I STILL CAN'T access myGlobal !!!}
Como você pode ver, como a chamada declaração de "classe estática", fooA e fooB ainda podem acessar o myGlobal. Mas ninguém mais pode. E ninguém mais fora deste CPP sabe que o foG e o myGlobal existem!
Ao contrário da "classe estática" caminhando nua com o catálogo de endereços tatuado na pele, o espaço para nome "anônimo" está totalmente vestido , o que parece um AFAIK muito melhor encapsulado.
Isso realmente importa?
A menos que os usuários do seu código sejam sabotadores (deixarei você, como exercício, descobrir como alguém pode acessar a parte privada de uma classe pública usando um truque sujo e indefinido ...), o que privateé private, mesmo que seja é visível noprivate seção de uma classe declarada em um cabeçalho.
Ainda assim, se você precisar adicionar outra "função privada" com acesso ao membro privado, ainda deverá declará-la para todo o mundo modificando o cabeçalho, o que é um paradoxo para mim: se eu alterar a implementação de meu código (a parte CPP), a interface (a parte HPP) NÃO deve mudar. Citando Leonidas: " Isso é ENCAPSULAÇÃO! "
Edit 20-09-2014
Quando os métodos estáticos das classes são realmente melhores que os namespaces com funções que não são membros?
Quando você precisar agrupar funções e alimentar esse grupo em um modelo:
namespace alpha
{void foo();void bar();}structBeta{staticvoid foo();staticvoid bar();};template<typename T>structGamma{void foobar(){
T::foo();
T::bar();}};Gamma<alpha> ga ;// compilation errorGamma<Beta> gb ;// ok
gb.foobar();// ok !!!
Porque, se uma classe pode ser um parâmetro de modelo, os espaços para nome não podem.
O GCC suporta -fno-access-control, que pode ser usado em testes de unidade de caixa branca para acessar os membros da classe privada. Essa é a única razão pela qual posso justificar o uso de um membro da classe em vez de um global anônimo / estático na implementação.
Tom
8
@ Tom: Uma solução multi-plataforma seria adicionar o seguinte código #define private publicnos cabeçalhos ... ^ _ ^ ...
paercebal
1
@ Tom: de qualquer maneira, IMHO, mesmo considerando o teste de unidade, os contras de "mostrar muita coisa" supera os profissionais. Eu acho que uma solução alternativa seria colocar o código a ser testado em uma função usando os parâmetros necessários (e não mais) em um utilitiesespaço para nome. Desta forma, esta função pode ser testado unidades, e ainda não têm acesso especial para os membros privados (como eles são dados como parâmetros na chamada de função) ...
paercebal
@ paercebal Estou prestes a pular a bordo do seu navio, mas tenho uma reserva final. Se alguém pular na sua namespacevontade, não terá acesso aos seus globalmembros, embora ocultos? Obviamente, eles teriam que adivinhar, mas, a menos que você esteja ofuscando seu código intencionalmente, nomes de variáveis são muito fáceis de adivinhar.
Zak
@Zak: De fato, eles poderiam, mas apenas tentando fazê-lo no arquivo CPP onde a variável myGlobal é declarada. O ponto é mais visibilidade do que acessibilidade. Na classe estática, a variável myGlobal é privada, mas ainda visível. Isso não é tão importante quanto parece, mas ainda assim, em uma DLL, mostrar um símbolo que deve ser privado para a DLL em um cabeçalho exportado pode ser estranho ... No espaço para nome, o myGlobal existe apenas no arquivo CPP (você pode ir ainda mais longe e torná-lo estático). Essa variável não aparece nos cabeçalhos públicos.
paercebal
63
Você também pode criar uma função livre em um espaço para nome:
Em alguns casos, você pode querer ter um encapsulamento de dados, mesmo que a classe seja principalmente "estática". Os alunos de classe particular estática darão a você isso. Os membros do espaço para nome são sempre públicos e não podem fornecer o encapsulamento de dados.
Torleif
Se o var "membro" for declarado e acessado apenas a partir do arquivo .cpp, será mais privado que um var privado declarado no arquivo .h. NÃO que eu recomende esta técnica.
precisa saber é o seguinte
3
@ Torleif: Você está errado. namespaces são melhores para encapsulamento do que membros privados estáticos. Veja minha resposta para demonstração.
paercebal
1
sim, mas no espaço para nome você deve manter a ordem da função, ao contrário da classe com membros estáticos, por exemplo, void a () {b ();} b () {} geraria um erro em um espaço para nome, mas não em uma classe com membros estáticos
Moataz Elmasry
13
Se você está procurando uma maneira de aplicar a palavra-chave "estática" a uma classe, como em C #, por exemplo
classes estáticas são apenas o compilador que o mantém em mãos e impede que você escreva quaisquer métodos / variáveis de instância.
Se você acabou de escrever uma classe normal sem nenhum método / variável de instância, é a mesma coisa, e é isso que você faria em C ++
Não para reclamar (especialmente para você), mas um compilador de mãos dadas para me impedir de escrever ou cortar / colar a palavra static200 vezes seria uma coisa boa.
3Dave
Concordou - mas uma classe estática em C # também não faz isso. Ele só não consegue compilar quando você esquecer de colar estática lá :-)
Orion Edwards
Sim - justo o suficiente. Minhas macros estão aparecendo. Honestamente, se eu declarar a classe como estática, o compilador só deve gerar um erro se tentar instancia-la. Regras que exigem que eu me repita são desagradáveis e devem ser as primeiras contra a parede quando a revolução chegar.
3Dave
11
No C ++, você deseja criar uma função estática de uma classe (não uma classe estática).
Alteração: No C ++, os especificadores estáticos ou externos podem ser aplicados apenas a nomes de objetos ou funções. O uso desses especificadores com declarações de tipo é ilegal no C ++. Em C, esses especificadores são ignorados quando usados em declarações de tipo. Exemplo:
staticstruct S {// valid C, invalid in C++int i;};
Justificativa: os especificadores de classe de armazenamento não têm significado quando associados a um tipo. No C ++, os membros da classe podem ser declarados com o especificador de classe de armazenamento estático. Permitir especificadores de classe de armazenamento nas declarações de tipo pode tornar o código confuso para os usuários.
E tipo struct,class também é uma declaração de tipo.
O mesmo pode ser deduzido percorrendo a árvore da sintaxe no Anexo A.
Como foi observado aqui, uma maneira melhor de conseguir isso em C ++ pode estar usando namespaces. Mas como ninguém mencionou a finalpalavra - chave aqui, estou publicando como seria um equivalente direto static classdo C # no C ++ 11 ou posterior:
classBitParser final
{public:BitParser()=delete;staticboolGetBitAt(int buffer,int pos);};boolBitParser::GetBitAt(int buffer,int pos){// your code}
Você 'pode' ter uma classe estática em C ++, como mencionado anteriormente, uma classe estática é aquela que não possui nenhum objeto dela instanciada. Em C ++, isso pode ser obtido declarando o construtor / destruidor como privado. O resultado final é o mesmo.
Isso é semelhante à maneira do C # de fazer isso em C ++
Em C # file.cs, você pode ter var privado dentro de uma função pública. Quando em outro arquivo, você pode usá-lo chamando o namespace com a função como em:
//Init the data (Link error if not done)intTheDataToBeHidden::_var1 =0;intTheDataToBeHidden::_var2 =0;//Implement the namespacenamespaceSharedData{voidSetError(constchar*Message,constchar*Title){//blah using TheDataToBeHidden::_var1, etc}voidDisplayError(void){//blah}}
OtherFile.h
#include"SharedModule.h"
OtherFile.cpp
//Call the functions using the hidden variablesSharedData::SetError("Hello","World");SharedData::DisplayError();
Mas todos Cango para TheDataToBeHidden -> Não é uma solução
Guy L
3
Diferente de outra linguagem de programação gerenciada, "classe estática" NÃO tem significado em C ++. Você pode fazer uso da função de membro estático.
Um caso em que os namespaces podem não ser tão úteis para obter "classes estáticas" é quando essas classes são usadas para obter composição sobre herança. Os espaços para nome não podem ser amigos das classes e, portanto, não podem acessar membros particulares de uma classe.
Uma (das muitas) alternativas, mas a mais (na minha opinião) mais elegante (em comparação ao uso de namespaces e construtores privados para emular o comportamento estático), a maneira de obter o comportamento de "classe que não pode ser instanciada" no C ++ seria: declare uma função virtual pura simulada com o privatemodificador de acesso.
Se você estiver usando C ++ 11, poderá percorrer uma milha extra para garantir que a classe não seja herdada (para emular puramente o comportamento de uma classe estática) usando o finalespecificador na declaração de classe para impedir que outras classes a herdem. .
// C++11 ONLYclassFoo final {public:staticint someMethod(int someArg);private:virtualvoid __dummy()=0;};
Por mais bobo e ilógico que possa parecer, o C ++ 11 permite a declaração de uma "função virtual pura que não pode ser substituída", que você pode usar juntamente com a declaração da classe finalpara implementar pura e completamente o comportamento estático, pois isso resulta na resultante classe para não ser herdável e a função fictícia para não ser substituída de forma alguma.
// C++11 ONLYclassFoo final {public:staticint someMethod(int someArg);private:// Other private declarationsvirtualvoid __dummy()=0 final;};// Foo now exhibits all the properties of a static class
Respostas:
Se você está procurando uma maneira de aplicar a palavra-chave "estática" a uma classe, como é possível em C #, por exemplo, não será possível sem usar o C ++ gerenciado.
Mas, pela aparência do seu exemplo, você só precisa criar um método estático público no seu objeto BitParser. Igual a:
BitParser.h
BitParser.cpp
Você pode usar esse código para chamar o método da mesma maneira que seu código de exemplo.
Espero que ajude! Felicidades.
fonte
private: BitParser() {}
Isso impedirá que alguém crie instâncias.BitParser() = delete;
transmitir adequadamente a intenção de remover o construtor (não apenas ocultando-o comoprivate
).Considere a solução de Matt Price .
O que você deseja é, expresso na semântica do C ++, colocar sua função (pois é uma função) em um espaço para nome.
Edit 2011-11-11
Não há "classe estática" em C ++. O conceito mais próximo seria uma classe com apenas métodos estáticos. Por exemplo:
Mas você deve se lembrar que "classes estáticas" são hacks no tipo de linguagem Java (por exemplo, C #) que são incapazes de ter funções não pertencentes a membros; portanto, eles precisam movê-las dentro das classes como métodos estáticos.
No C ++, o que você realmente deseja é uma função que não seja membro que você declarará em um espaço para nome:
Por que é que?
No C ++, o espaço para nome é mais poderoso que as classes para o padrão "método estático Java", porque:
Conclusão: Não copie / cole esse padrão Java / C # em C ++. Em Java / C #, o padrão é obrigatório. Mas em C ++, é um estilo ruim.
Edit 2010-06-10
Houve um argumento a favor do método estático porque, às vezes, é necessário usar uma variável de membro privado estático.
Discordo um pouco, como mostra a seguir:
A solução "Membro particular estático"
Primeiro, myGlobal é chamado myGlobal porque ainda é uma variável privada global. Uma olhada na fonte do CPP esclarecerá que:
À primeira vista, o fato de a função livre barC não poder acessar Foo :: myGlobal parece uma coisa boa do ponto de vista do encapsulamento ... É legal porque alguém olhando para o HPP não poderá (a menos que recorra à sabotagem) acessar Foo :: myGlobal.
Mas se você olhar atentamente, verá que é um erro colossal: não apenas sua variável privada ainda deve ser declarada no HPP (e, portanto, visível para todo o mundo, apesar de ser privado), mas você deve declarar no mesmo HPP todas as funções (como em TODAS) que serão autorizadas a acessá-lo !!!
Portanto, usar um membro estático privado é como andar nu, com a lista de seus amantes tatuados na pele: ninguém está autorizado a tocar, mas todos podem espiar. E o bônus: todos podem ter o nome daqueles autorizados a jogar com suas privadas.
private
de fato ... :-DA solução "namespaces anônimos"
Os namespaces anônimos terão a vantagem de tornar as coisas privadas realmente privadas.
Primeiro, o cabeçalho HPP
Apenas para ter certeza de que você observou: Não há declaração inútil de barB nem myGlobal. O que significa que ninguém lendo o cabeçalho sabe o que está escondido atrás da barraA.
Então, o CPP:
Como você pode ver, como a chamada declaração de "classe estática", fooA e fooB ainda podem acessar o myGlobal. Mas ninguém mais pode. E ninguém mais fora deste CPP sabe que o foG e o myGlobal existem!
Ao contrário da "classe estática" caminhando nua com o catálogo de endereços tatuado na pele, o espaço para nome "anônimo" está totalmente vestido , o que parece um AFAIK muito melhor encapsulado.
Isso realmente importa?
A menos que os usuários do seu código sejam sabotadores (deixarei você, como exercício, descobrir como alguém pode acessar a parte privada de uma classe pública usando um truque sujo e indefinido ...), o que
private
éprivate
, mesmo que seja é visível noprivate
seção de uma classe declarada em um cabeçalho.Ainda assim, se você precisar adicionar outra "função privada" com acesso ao membro privado, ainda deverá declará-la para todo o mundo modificando o cabeçalho, o que é um paradoxo para mim: se eu alterar a implementação de meu código (a parte CPP), a interface (a parte HPP) NÃO deve mudar. Citando Leonidas: " Isso é ENCAPSULAÇÃO! "
Edit 20-09-2014
Quando os métodos estáticos das classes são realmente melhores que os namespaces com funções que não são membros?
Quando você precisar agrupar funções e alimentar esse grupo em um modelo:
Porque, se uma classe pode ser um parâmetro de modelo, os espaços para nome não podem.
fonte
#define private public
nos cabeçalhos ... ^ _ ^ ...utilities
espaço para nome. Desta forma, esta função pode ser testado unidades, e ainda não têm acesso especial para os membros privados (como eles são dados como parâmetros na chamada de função) ...namespace
vontade, não terá acesso aos seusglobal
membros, embora ocultos? Obviamente, eles teriam que adivinhar, mas, a menos que você esteja ofuscando seu código intencionalmente, nomes de variáveis são muito fáceis de adivinhar.Você também pode criar uma função livre em um espaço para nome:
No BitParser.h
No BitParser.cpp
Em geral, essa seria a maneira preferida de escrever o código. Quando não há necessidade de um objeto, não use uma classe.
fonte
classes estáticas são apenas o compilador que o mantém em mãos e impede que você escreva quaisquer métodos / variáveis de instância.
Se você acabou de escrever uma classe normal sem nenhum método / variável de instância, é a mesma coisa, e é isso que você faria em C ++
fonte
static
200 vezes seria uma coisa boa.No C ++, você deseja criar uma função estática de uma classe (não uma classe estática).
Você poderá chamar a função usando BitParser :: getBitAt () sem instanciar um objeto que eu presumo ser o resultado desejado.
fonte
Posso escrever algo como
static class
?Não , de acordo com o rascunho padrão do C ++ 11 N3337 anexo C 7.1.1 da :
E tipo
struct
,class
também é uma declaração de tipo.O mesmo pode ser deduzido percorrendo a árvore da sintaxe no Anexo A.
É interessante notar que isso
static struct
era legal em C, mas não teve efeito: por que e quando usar estruturas estáticas na programação C?fonte
Como foi observado aqui, uma maneira melhor de conseguir isso em C ++ pode estar usando namespaces. Mas como ninguém mencionou a
final
palavra - chave aqui, estou publicando como seria um equivalente diretostatic class
do C # no C ++ 11 ou posterior:fonte
Você 'pode' ter uma classe estática em C ++, como mencionado anteriormente, uma classe estática é aquela que não possui nenhum objeto dela instanciada. Em C ++, isso pode ser obtido declarando o construtor / destruidor como privado. O resultado final é o mesmo.
fonte
No C ++ gerenciado, a sintaxe da classe estática é: -
... Antes tarde do que nunca...
fonte
Isso é semelhante à maneira do C # de fazer isso em C ++
Em C # file.cs, você pode ter var privado dentro de uma função pública. Quando em outro arquivo, você pode usá-lo chamando o namespace com a função como em:
Veja como calcular o mesmo em C ++:
SharedModule.h
SharedModule.cpp
OtherFile.h
OtherFile.cpp
fonte
Diferente de outra linguagem de programação gerenciada, "classe estática" NÃO tem significado em C ++. Você pode fazer uso da função de membro estático.
fonte
Um caso em que os namespaces podem não ser tão úteis para obter "classes estáticas" é quando essas classes são usadas para obter composição sobre herança. Os espaços para nome não podem ser amigos das classes e, portanto, não podem acessar membros particulares de uma classe.
fonte
Uma (das muitas) alternativas, mas a mais (na minha opinião) mais elegante (em comparação ao uso de namespaces e construtores privados para emular o comportamento estático), a maneira de obter o comportamento de "classe que não pode ser instanciada" no C ++ seria: declare uma função virtual pura simulada com o
private
modificador de acesso.Se você estiver usando C ++ 11, poderá percorrer uma milha extra para garantir que a classe não seja herdada (para emular puramente o comportamento de uma classe estática) usando o
final
especificador na declaração de classe para impedir que outras classes a herdem. .Por mais bobo e ilógico que possa parecer, o C ++ 11 permite a declaração de uma "função virtual pura que não pode ser substituída", que você pode usar juntamente com a declaração da classe
final
para implementar pura e completamente o comportamento estático, pois isso resulta na resultante classe para não ser herdável e a função fictícia para não ser substituída de forma alguma.fonte