Question

Comment créer une classe statique en C++ ?Je devrais pouvoir faire quelque chose comme :

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

En supposant que j'ai créé le BitParser classe.Quel serait le BitParser à quoi ressemble la définition de classe ?

Était-ce utile?

La solution

Si vous cherchez un moyen d'appliquer le mot-clé "static" à une classe, comme vous pouvez le faire en C# par exemple, vous ne pourrez pas le faire sans utiliser le C++ managé.

Mais à en juger par votre exemple, il vous suffit de créer une méthode statique publique sur votre objet 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 exemple de code.

J'espère que cela pourra aider!Acclamations.

Autres conseils

Considérer La solution de Matt Price.

  1. En C++, une « classe statique » n’a aucune signification.La chose la plus proche est une classe avec uniquement des méthodes et des membres statiques.
  2. L'utilisation de méthodes statiques ne fera que vous limiter.

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

Modifier 2011-11-11

Il n’existe 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 ex.C#) qui ne peuvent pas avoir de fonctions non membres, ils doivent donc les déplacer à l'intérieur des classes en tant que 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 « Méthode statique Java », car :

  • les méthodes statiques ont accès aux symboles privés des classes
  • les méthodes statiques privées sont toujours visibles (si inaccessibles) par tout le monde, ce qui viole quelque peu l'encapsulation
  • les méthodes statiques ne peuvent pas être déclarées en avant
  • 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 puisse être fait mieux 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 modèle Java/C# en C++.En Java/C#, le modèle est obligatoire.Mais en C++, c'est un mauvais style.

Modifier 2010-06-10

Il y a eu un argument en faveur de la méthode statique car parfois, il faut utiliser une variable membre privée statique.

Je suis quelque peu en désaccord, comme le montre ci-dessous :

La solution « Membre privé statique »

// HPP

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

Premièrement, myGlobal est appelé myGlobal car il s'agit toujours d'une variable privée globale.Un examen de la source du RPC permettra de clarifier ce qui suit :

// 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 !!!
}

À première vue, le fait que la fonction gratuite barC ne puisse pas accéder à Foo::myGlobal semble une bonne chose du point de vue de l'encapsulation...C'est cool parce que quelqu'un qui regarde le HPP ne pourra pas (à moins de recourir au sabotage) d'accéder à Foo::myGlobal.

Mais si vous y regardez de près, vous constaterez qu’il s’agit d’une erreur colossale :Non seulement votre variable privée doit toujours être déclarée dans le HPP (et donc visible par tout le monde, bien qu'elle soit privée), mais vous devez déclarer dans le même HPP toutes (comme dans TOUTES) les fonctions qui seront autorisées à y accéder ! !!

Donc utiliser un membre statique privé, c'est comme marcher dehors nu avec la liste de vos amants tatouée sur votre peau :Personne n’est autorisé à toucher, mais tout le monde peut jeter un coup d’œil.Et le bonus :Chacun peut avoir le nom des personnes autorisées à jouer avec vos toilettes.

private en effet...:-D

La solution "Espaces de noms anonymes"

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

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

// HPP

namespace Foo
{
   void barA() ;
}

Juste pour être sûr que vous avez remarqué :Il n'y a 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 RPC :

// 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 !!!
}

Comme vous pouvez le voir, comme pour 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 !

Contrairement à la "classe statique" marchant nue avec son carnet d'adresses tatoué sur sa peau, l'espace de noms "anonyme" est entièrement habillé., ce qui semble bien mieux encapsulé AFAIK.

Est-ce que c'est vraiment important?

A moins que les utilisateurs de votre code ne soient des saboteurs (je vous laisse, en exercice, trouver comment on peut accéder à la partie privée d'une classe publique à l'aide d'un sale hack au comportement non défini...), qu'est-ce que c'est ? private est private, même s'il est visible dans le private section d'une classe déclarée dans un en-tête.

Néanmoins, si vous devez ajouter une autre "fonction privée" avec accès au membre privé, vous devez quand même la déclarer au monde entier en modifiant l'en-tête, ce qui est un paradoxe à mon avis : Si je change l'implémentation de mon code (la partie CPP), alors l'interface (la partie HPP) ne devrait PAS changer. Citant Léonidas :"C'est de l'ENCAPSULATION !"

Modifier 20/09/2014

Quand les méthodes statiques des 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 vers un modèle :

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 !!!

Parce que, si une classe peut être un paramètre de modèle, un espace de noms ne le 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 meilleure façon d’écrire le code.Lorsqu’un objet n’est pas nécessaire, 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 ne sont que 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 souhaitez 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 objet qui, je suppose, est 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 :

Changement:En C++, les spécificateurs static ou extern ne peuvent être appliqués qu'aux noms d'objets 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 les déclarations de type.Exemple:

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

Raisonnement:Les spécificateurs de classe de stockage n’ont aucune signification lorsqu’ils sont associés à un type.En C ++, les membres de la 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 déroutant pour les utilisateurs.

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

La même chose peut être déduite en parcourant l’arbre syntaxique de l’Annexe A.

Il est intéressant de noter que static struct était légal en C, mais n'avait aucun effet : Pourquoi et quand utiliser des structures statiques en programmation C ?

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

En Managed C++, la syntaxe de classe statique est : -

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

...Mieux vaut tard que jamais...

Ceci est similaire à la manière de procéder de C# en C++

Dans C# file.cs, vous pouvez avoir une variable privée dans une fonction publique.Dans un autre fichier, vous pouvez l'utiliser en appelant l'espace de noms avec la fonction comme dans :

MyNamespace.Function(blah);

Voici comment faire la même chose 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, la « 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 consister à utiliser des espaces de noms.Mais comme personne n'a mentionné le final mot-clé ici, je publie quel équivalent direct de static class à partir de C# ressemblerait à 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 peuvent ne pas être très utiles pour réaliser des « classes statiques » est celui de l'utilisation de ces classes pour réaliser une composition sur héritage.Les espaces de noms ne peuvent pas être amis des 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 <typename T>
  static void bar(T& t) {
    t.member = 1;
  }
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top