Comment créez-vous une classe statique en C ++?

Comment créez-vous une classe statique en C ++? Je devrais être capable de faire quelque chose comme:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl; 

En supposant que j’ai créé la classe BitParser . À quoi ressemblerait la définition de la classe BitParser ?

Si vous cherchez un moyen d’appliquer le mot-clé “static” à une classe, comme vous pouvez le faire avec C # par exemple, alors vous ne pourrez pas utiliser Managed C ++.

Mais à quoi ressemble votre exemple, il vous suffit de créer une méthode statique publique sur votre object BitParser. Ainsi:

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; } 

Vous pouvez utiliser ce code pour appeler la méthode de la même manière que votre code d’exemple.

J’espère que cela pourra aider! À votre santé.

Considérons la solution de Matt Price .

  1. En C ++, une “classe statique” n’a pas de sens. La chose la plus proche est une classe avec uniquement des méthodes statiques et des membres.
  2. Utiliser des méthodes statiques ne vous limitera que

Ce que vous voulez est, exprimé en sémantique C ++, de mettre votre fonction (car c’est une fonction) dans un espace de noms.

Modifier 2011-11-11

Il n’y a pas de “classe statique” en C ++. Le concept le plus proche serait une classe avec uniquement des méthodes statiques. Par exemple:

 // header class MyClass { public : static void myMethod() ; } ; // source void MyClass::myMethod() { // etc. } 

Mais vous devez vous rappeler que les “classes statiques” sont des hacks dans les langages de type Java (par exemple C #) qui ne peuvent pas avoir de fonctions non-membres. Ils doivent donc les déplacer dans des classes comme méthodes statiques.

En C ++, ce que vous voulez vraiment, c’est une fonction non membre que vous déclarerez dans un espace de noms:

 // header namespace MyNamespace { void myMethod() ; } // source namespace MyNamespace { void myMethod() { // etc. } } 

Pourquoi donc?

En C ++, l’espace de noms est plus puissant que les classes pour le modèle “Java static method”, car:

  • les méthodes statiques ont access aux symboles privés des classes
  • les méthodes statiques privées sont toujours visibles (si inaccessibles) pour tout le monde, ce qui viole quelque peu l’encapsulation
  • les méthodes statiques ne peuvent pas être déclarées d’avance
  • les méthodes statiques ne peuvent pas être surchargées par l’utilisateur de la classe sans modifier l’en-tête de la bibliothèque
  • il n’y a rien qui puisse être fait par une méthode statique qui ne peut pas être mieux faite qu’une fonction non-membre (éventuellement amie) dans le même espace de noms
  • les espaces de noms ont leur propre sémantique (ils peuvent être combinés, ils peuvent être anonymes, etc.)
  • etc.

Conclusion: ne copiez / collez pas le motif de ce Java / C # en C ++. En Java / C #, le modèle est obligatoire. Mais en C ++, c’est du mauvais style.

Modifier 2010-06-10

Il y avait un argument en faveur de la méthode statique car il faut parfois utiliser une variable membre statique.

Je suis un peu en désaccord, comme montré ci-dessous:

La solution “Membre privé statique”

 // HPP class Foo { public : void barA() ; private : void barB() ; static std::ssortingng myGlobal ; } ; 

Tout d’abord, myGlobal s’appelle myGlobal car il s’agit toujours d’une variable privée globale. Un examen de la source du RPC permettra de préciser que:

 // CPP std::ssortingng 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 !!! } 

À première vue, le fait que la fonction libre barC ne puisse pas accéder à Foo :: myGlobal semble être une bonne chose du sharepoint vue de l’encapsulation… C’est cool parce que quelqu’un qui regarde le HPP ne pourra pas y accéder Foo :: myGlobal.

Mais si vous le regardez de près, vous verrez que c’est une erreur colossale: non seulement votre variable privée doit encore être déclarée dans le HPP (et donc visible dans le monde entier, malgré qu’elle soit privée), mais vous devez déclarer dans la même HPP toutes les fonctions (comme dans TOUTES) qui seront autorisées à y accéder !!!

Donc, utiliser un membre statique privé, c’est comme sortir dehors nu avec la liste de vos amants tatoués sur la peau: Personne n’est autorisé à toucher, mais tout le monde peut le voir. Et le bonus: tout le monde peut avoir les noms de ceux qui sont autorisés à jouer avec vos affaires.

private effet … 😀

La solution “Anonymous namespaces”

Les espaces de noms anonymes auront l’avantage de rendre les choses privées et privées.

Tout d’abord, l’en-tête HPP

 // HPP namespace Foo { void barA() ; } 

Juste pour être sûr que vous avez fait remarquer: il n’ya pas de déclaration inutile de barB ni de myGlobal. Ce qui signifie que personne qui lit l’en-tête ne sait ce qui se cache derrière BarA.

Ensuite, le CPP:

 // CPP namespace Foo { namespace { std::ssortingng myGlobal ; void Foo::barB() { // I can access Foo::myGlobal } } void barA() { // I can access myGlobal, too } } void barC() { // I STILL CAN'T access myGlobal !!! } 

Comme vous pouvez le constater, tout comme la déclaration dite de “classe statique”, fooA et fooB peuvent toujours accéder à myGlobal. Mais personne d’autre ne le peut. Et personne d’autre en dehors de ce CPP ne sait que fooB et myGlobal existent même!

Contrairement à la “classe statique” marchant sur le nu avec son carnet d’adresses tatoué sur sa peau, l’espace de noms “anonyme” est entièrement habillé , ce qui semble bien mieux encapsulé dans AFAIK.

Est-ce que c’est vraiment important?

A moins que les utilisateurs de votre code ne soient des saboteurs (je vous laisse, en tant qu’exercice, découvrir comment accéder à la partie privée d’une classe publique en utilisant un hack de comportement non défini), ce qui est private est private , même s’il est visible dans la section private d’une classe déclarée dans un en-tête.

Cependant, si vous avez besoin d’append une autre “fonction privée” ayant access au membre privé, vous devez toujours le déclarer au monde entier en modifiant l’en-tête, ce qui est un paradoxe pour moi: si je modifie la mise en œuvre de mon code (la partie CPP), alors l’interface (la partie HPP) ne doit PAS changer. Citant Leonidas: ” C’est ENCAPSULATION!

Modifier 2014-09-20

Quand les classes sont-elles réellement meilleures que les espaces de noms avec des fonctions non membres?

Lorsque vous devez regrouper des fonctions et alimenter ce groupe en un modèle:

 namespace alpha { void foo() ; void bar() ; } struct Beta { static void foo() ; static void bar() ; }; template  struct Gamma { void foobar() { T::foo() ; T::bar() ; } }; Gamma ga ; // compilation error Gamma gb ; // ok gb.foobar() ; // ok !!! 

Parce que, si une classe peut être un paramètre de modèle, un espace de noms ne peut pas.

Vous pouvez également créer une fonction gratuite dans un espace de noms:

Dans BitParser.h

 namespace BitParser { bool getBitAt(int buffer, int bitIndex); } 

Dans BitParser.cpp

 namespace BitParser { bool getBitAt(int buffer, int bitIndex) { //get the bit :) } } 

En général, ce serait la manière préférée d’écrire le code. Lorsqu’il n’y a pas besoin d’object, n’utilisez pas de classe.

Si vous cherchez un moyen d’appliquer le mot-clé “static” à une classe, comme vous pouvez le faire en C # par exemple

Les classes statiques sont juste le compilateur qui vous tient à la main et vous empêche d’écrire des méthodes / variables d’instance.

Si vous écrivez simplement une classe normale sans aucune méthode / variable d’instance, c’est la même chose, et c’est ce que vous feriez en C ++

En C ++, vous voulez créer une fonction statique d’une classe (pas une classe statique).

 class BitParser { public: ... static ... getBitAt(...) { } }; 

Vous devriez alors pouvoir appeler la fonction en utilisant BitParser :: getBitAt () sans instancier un object que je présume être le résultat souhaité.

Puis-je écrire quelque chose comme static class ?

Non , selon le projet de norme C ++ 11 N3337, annexe C 7.1.1:

Modification: En C ++, les spécificateurs static ou extern ne peuvent être appliqués qu’aux noms d’objects ou de fonctions. L’utilisation de ces spécificateurs avec des déclarations de type est illégale en C ++. En C, ces spécificateurs sont ignorés lorsqu’ils sont utilisés sur des déclarations de type. Exemple:

 static struct S { // valid C, invalid in C++ int i; }; 

Justification: Les spécificateurs de classe de stockage n’ont aucune signification lorsqu’ils sont associés à un type. En C ++, les membres de classe peuvent être déclarés avec le spécificateur de classe de stockage statique. Autoriser les spécificateurs de classe de stockage sur les déclarations de type pourrait rendre le code confus pour les utilisateurs.

Et comme struct , la class est aussi une déclaration de type.

On peut en déduire la même chose en parcourant l’arbre de syntaxe dans l’annexe A.

Il est intéressant de noter que static struct était légale en C, mais n’avait aucun effet: pourquoi et quand utiliser des structures statiques dans la programmation en C?

Vous pouvez avoir une classe statique en C ++, comme mentionné précédemment, une classe statique en est une qui n’a aucun object instancié. En C ++, cela peut être obtenu en déclarant le constructeur / destructeur comme privé. Le résultat final est le même.

Dans Managed C ++, la syntaxe de classe statique est la suivante: –

 public ref class BitParser abstract sealed { public: static bool GetBitAt(...) { ... } } 

… Mieux vaut tard que jamais…

Ceci est similaire à la façon de faire de C # en C ++

Dans C # file.cs, vous pouvez avoir private var dans une fonction publique. Lorsque dans un autre fichier, vous pouvez l’utiliser en appelant l’espace de noms avec la fonction comme dans:

 MyNamespace.Function(blah); 

Voici comment imp avec le même en 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 } } 

AutreFichier.h

 #include "SharedModule.h" 

AutreFichier.cpp

 //Call the functions using the hidden variables SharedData::SetError("Hello", "World"); SharedData::DisplayError(); 

Contrairement à d’autres langages de programmation gérés, “classe statique” n’a aucune signification en C ++. Vous pouvez utiliser la fonction membre statique.

Comme cela a été noté ici, une meilleure façon d’y parvenir en C ++ pourrait être d’utiliser des espaces de noms. Mais comme personne n’a mentionné le mot-clé final ici, je publie à quoi ressemblerait un équivalent direct de static class de C # dans C ++ 11 ou version ultérieure:

 class BitParser final { public: BitParser() = delete; static bool GetBitAt(int buffer, int pos); }; bool BitParser::GetBitAt(int buffer, int pos) { // your code } 

Un cas où les espaces de noms ne sont peut-être pas si utiles pour obtenir des “classes statiques” consiste à utiliser ces classes pour obtenir une composition par rapport à l’inheritance. Les espaces de noms ne peuvent pas être des amis de classes et ne peuvent donc pas accéder aux membres privés d’une classe.

 class Class { public: void foo() { Static::bar(*this); } private: int member{0}; friend class Static; }; class Static { public: template  static void bar(T& t) { t.member = 1; } };