Wie erstellt man eine statische Klasse in C++?

Wie erstellt man eine statische Klasse in C++?

Wenn Sie nach einer Möglichkeit suchen, das Schlüsselwort „static“ auf eine Klasse anzuwenden, wie Sie es beispielsweise in C# können, dann kommen Sie ohne Managed C++ nicht weiter.

Aber wie Ihr Beispiel aussieht, müssen Sie nur eine öffentliche statische Methode für Ihr BitParser-Objekt erstellen. So:

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

Sie können diesen Code verwenden, um die Methode auf die gleiche Weise wie Ihren Beispielcode aufzurufen.

Ich hoffe, das hilft! Prost.


Betrachten Sie die Lösung von Matt Price.

  1. In C++ hat eine "statische Klasse" keine Bedeutung. Am nächsten kommt eine Klasse mit nur statischen Methoden und Membern.
  2. Die Verwendung statischer Methoden wird Sie nur einschränken.

Was Sie wollen, ist, ausgedrückt in C++-Semantik, Ihre Funktion (denn es ist eine Funktion) in einem Namespace.

Bearbeiten 11.11.2011

In C++ gibt es keine "statische Klasse". Das nächste Konzept wäre eine Klasse mit nur statischen Methoden. Zum Beispiel:

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

// source
void MyClass::myMethod()
{
   // etc.
}

Aber Sie müssen bedenken, dass "statische Klassen" Hacks in Java-ähnlichen Sprachen (z. B. C#) sind, die keine Nicht-Member-Funktionen haben können, also müssen sie sie stattdessen als statische Methoden in Klassen verschieben.

Was Sie in C++ wirklich wollen, ist eine Nicht-Member-Funktion, die Sie in einem Namensraum deklarieren:

// header
namespace MyNamespace
{
   void myMethod() ;
}

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

Warum ist das so?

In C++ ist der Namespace leistungsfähiger als Klassen für das Muster „Java static method“, weil:

  • Statische Methoden haben Zugriff auf die privaten Symbole der Klasse
  • private statische Methoden sind immer noch für alle sichtbar (wenn sie nicht zugänglich sind), was etwas gegen die Kapselung verstößt
  • Statische Methoden können nicht vorwärts deklariert werden
  • Statische Methoden können vom Klassenbenutzer nicht überladen werden, ohne den Bibliotheksheader zu ändern
  • Es gibt nichts, was mit einer statischen Methode nicht besser gemacht werden kann als eine (möglicherweise befreundete) Nicht-Member-Funktion im selben Namespace
  • Namespaces haben ihre eigene Semantik (sie können kombiniert werden, sie können anonym sein usw.)
  • usw.

Fazit:Kopieren Sie nicht das Muster von Java/C# in C++. In Java/C# ist das Muster obligatorisch. Aber in C++ ist es schlechter Stil.

Bearbeiten 10.06.2010

Es gab ein Argument zugunsten der statischen Methode, weil man manchmal eine statische private Mitgliedsvariable verwenden muss.

Ich stimme etwas nicht zu, wie unten gezeigt:

Die Lösung "Statisches privates Mitglied"

// HPP

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

Erstens heißt myGlobal myGlobal, weil es immer noch eine globale private Variable ist. Ein Blick auf die CPP-Quelle wird das verdeutlichen:

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

Auf den ersten Blick scheint die Tatsache, dass die freie Funktion barC nicht auf Foo::myGlobal zugreifen kann, aus Sicht der Kapselung eine gute Sache zu sein ... Es ist cool, weil jemand, der sich das HPP ansieht, nicht in der Lage sein wird (es sei denn, er greift auf Sabotage zurück). Foo::myGlobal.

Aber wenn Sie genau hinsehen, werden Sie feststellen, dass es sich um einen kolossalen Fehler handelt:Ihre private Variable muss nicht nur weiterhin im HPP deklariert werden (und damit für alle Welt sichtbar, obwohl sie privat ist), sondern Sie müssen deklarieren im selben HPP alle (wie in ALL) Funktionen, die berechtigt sind, darauf zuzugreifen !!!

Die Verwendung eines privaten statischen Mitglieds ist also, als würde man nackt nach draußen gehen, mit der Liste Ihrer Liebhaber, die auf Ihre Haut tätowiert sind:Niemand ist berechtigt, sie zu berühren, aber jeder kann einen Blick darauf werfen. Und der Bonus:Jeder kann die Namen derjenigen haben, die berechtigt sind, mit Ihren Eingeweihten zu spielen.

private ja... :-D

Die "Anonyme Namespaces"-Lösung

Anonyme Namensräume haben den Vorteil, Dinge wirklich privat zu machen.

Zuerst der HPP-Header

// HPP

namespace Foo
{
   void barA() ;
}

Nur um sicherzugehen, dass Sie bemerkt haben:Es gibt keine nutzlose Deklaration von barB oder myGlobal. Was bedeutet, dass niemand, der den Header liest, weiß, was sich hinter barA verbirgt.

Dann das 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 !!!
}

Wie Sie sehen können, können fooA und fooB wie die sogenannte "statische Klassendeklaration" immer noch auf myGlobal zugreifen. Aber das kann sonst niemand. Und niemand außerhalb dieser CPP weiß, dass fooB und myGlobal überhaupt existieren!

Anders als die "statische Klasse", die nackt mit ihrem Adressbuch auf der Haut tätowiert ist, ist der "anonyme" Namensraum vollständig bekleidet , was ziemlich besser gekapselt zu sein scheint, AFAIK.

Ist das wirklich wichtig?

Sofern die Benutzer Ihres Codes keine Saboteure sind (ich lasse Sie als Übung herausfinden, wie man mit einem schmutzigen Verhaltens-undefinierten Hack auf den privaten Teil einer öffentlichen Klasse zugreifen kann ...), was ist private ist private , auch wenn es im private sichtbar ist Abschnitt einer Klasse, der in einem Header deklariert ist.

Wenn Sie jedoch eine weitere "private Funktion" mit Zugriff auf das private Mitglied hinzufügen müssen, müssen Sie sie dennoch der ganzen Welt mitteilen, indem Sie den Header ändern, was für mich ein Paradoxon ist:Wenn ich mich ändere die Implementierung meines Codes (der CPP-Teil), dann sollte sich die Schnittstelle (der HPP-Teil) NICHT ändern. Zitat von Leonidas:"Das ist ENCAPSULATION! "

Bearbeitet am 20.09.2014

Wann sind statische Methoden von Klassen eigentlich besser als Namespaces mit Nicht-Member-Funktionen?

Wenn Sie Funktionen zusammenfassen und diese Gruppe einer Vorlage zuführen müssen:

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

Denn wenn eine Klasse ein Template-Parameter sein kann, kann ein Namespace dies nicht.


Sie können auch eine freie Funktion in einem Namensraum erstellen:

In BitParser.h

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

In BitParser.cpp

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

Im Allgemeinen wäre dies die bevorzugte Art, den Code zu schreiben. Wenn kein Objekt benötigt wird, verwenden Sie keine Klasse.