Como você cria uma classe estática em C ++? Eu deveria ser capaz de fazer algo como:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
Supondo que eu criei a BitParser
classe. Como seria a BitParser
definição de classe?
Como você cria uma classe estática em C ++? Eu deveria ser capaz de fazer algo como:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
Supondo que eu criei a BitParser
classe. Como seria a BitParser
definição de classe?
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
class BitParser
{
public:
static bool getBitAt(int buffer, int bitIndex);
// ...lots of great stuff
private:
// Disallow creating an instance of this object
BitParser() {}
};
BitParser.cpp
bool BitParser::getBitAt(int buffer, int bitIndex)
{
bool isBitSet = false;
// .. determine if bit is set
return isBitSet;
}
Você pode usar esse código para chamar o método da mesma maneira que seu código de exemplo.
Espero que ajude! Felicidades.
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 como private
).
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.
Não há "classe estática" em C ++. O conceito mais próximo seria uma classe com apenas métodos estáticos. Por exemplo:
// header
class MyClass
{
public :
static void myMethod() ;
} ;
// source
void MyClass::myMethod()
{
// etc.
}
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:
// header
namespace MyNamespace
{
void myMethod() ;
}
// source
namespace MyNamespace
{
void myMethod()
{
// etc.
}
}
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.
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:
// HPP
class Foo
{
public :
void barA() ;
private :
void barB() ;
static std::string myGlobal ;
} ;
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 CPP
void Foo::barA()
{
// I can access Foo::myGlobal
}
void Foo::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
Os namespaces anônimos terão a vantagem de tornar as coisas privadas realmente privadas.
Primeiro, o cabeçalho HPP
// HPP
namespace Foo
{
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:
// CPP
namespace Foo
{
namespace
{
std::string myGlobal ;
void Foo::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.
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! "
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() ;
}
struct Beta
{
static void foo() ;
static void bar() ;
};
template <typename T>
struct Gamma
{
void foobar()
{
T::foo() ;
T::bar() ;
}
};
Gamma<alpha> ga ; // compilation error
Gamma<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.
#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 seus global
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
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
No BitParser.cpp
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
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.
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 ++
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).
class BitParser {
public:
...
static ... getBitAt(...) {
}
};
Você poderá chamar a função usando BitParser :: getBitAt () sem instanciar um objeto que eu presumo ser o resultado desejado.
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 :
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:
static struct 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.
É 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?
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 direto static class
do C # no C ++ 11 ou posterior:
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::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:
MyNamespace.Function(blah);
Veja como calcular o mesmo em C ++:
SharedModule.h
class TheDataToBeHidden
{
public:
static int _var1;
static int _var2;
};
namespace SharedData
{
void SetError(const char *Message, const char *Title);
void DisplayError(void);
}
SharedModule.cpp
//Init the data (Link error if not done)
int TheDataToBeHidden::_var1 = 0;
int TheDataToBeHidden::_var2 = 0;
//Implement the namespace
namespace SharedData
{
void SetError(const char *Message, const char *Title)
{
//blah using TheDataToBeHidden::_var1, etc
}
void DisplayError(void)
{
//blah
}
}
OtherFile.h
#include "SharedModule.h"
OtherFile.cpp
//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();
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.
class Class {
public:
void foo() { Static::bar(*this); }
private:
int member{0};
friend class Static;
};
class Static {
public:
template <typename T>
static void bar(T& t) {
t.member = 1;
}
};
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.
class Foo {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
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. .
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
virtual void __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 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.
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
// Other private declarations
virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class