Frage

Wie erstellt man eine statische Klasse in C++?Ich sollte in der Lage sein, so etwas zu tun:

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

Vorausgesetzt, ich habe das erstellt BitParser Klasse.Was würde das BitParser Wie sieht die Klassendefinition aus?

War es hilfreich?

Lösung

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

Aber wie Ihr Beispiel aussieht, müssen Sie lediglich eine öffentliche statische Methode für Ihr BitParser-Objekt erstellen.Etwa 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;
}

Mit diesem Code können Sie die Methode auf die gleiche Weise wie Ihren Beispielcode aufrufen.

Hoffentlich hilft das!Prost.

Andere Tipps

In Betracht ziehen Die Lösung von Matt Price.

  1. In C++ hat eine „statische Klasse“ keine Bedeutung.Das nächste Ding ist eine Klasse mit nur statischen Methoden und Mitgliedern.
  2. Die Verwendung statischer Methoden schränkt Sie nur ein.

Was Sie wollen, ist, ausgedrückt in der C++-Semantik, Ihre Funktion (dafür) zu platzieren 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 sind (z. B.C#), die keine Nicht-Member-Funktionen haben können und diese stattdessen als statische Methoden in Klassen verschieben müssen.

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

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

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

Warum das?

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

  • Statische Methoden haben Zugriff auf die privaten Symbole der Klasse
  • Private statische Methoden sind immer noch für alle sichtbar (wenn auch nicht zugänglich), was die Kapselung etwas verletzt
  • Statische Methoden können nicht vorwärtsdeklariert werden
  • Statische Methoden können vom Klassenbenutzer nicht überladen werden, ohne den Bibliotheksheader zu ändern
  • Es gibt nichts, was eine statische Methode nicht besser machen könnte als eine (möglicherweise befreundete) Nichtmitgliedsfunktion im selben Namespace
  • Namespaces haben ihre eigene Semantik (sie können kombiniert werden, sie können anonym sein usw.)
  • usw.

Abschluss:Kopieren/fügen Sie das Java/C#-Muster nicht in C++ ein.In Java/C# ist das Muster obligatorisch.Aber in C++ ist es ein schlechter Stil.

Bearbeiten 10.06.2010

Es gab ein Argument für die statische Methode, da man manchmal eine statische private Mitgliedsvariable verwenden muss.

Ich bin etwas anderer Meinung, 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 Folgendes 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 auf Foo::myGlobal zugreifen kann (es sei denn, er greift auf Sabotage zurück).

Aber wenn man es genau betrachtet, wird man feststellen, dass es sich um einen kolossalen Fehler handelt:Nicht nur, dass Ihre private Variable weiterhin im HPP deklariert sein muss (und daher für die ganze Welt sichtbar ist, obwohl sie privat ist), sondern Sie müssen im selben HPP alle (wie in ALLEN) Funktionen deklarieren, die zum Zugriff darauf berechtigt sind! !!

Also Die Verwendung eines privaten statischen Mitglieds ist, als würde man nackt mit der Liste seiner Liebhaber auf der Haut tätowiert nach draußen gehen:Niemand hat die Berechtigung zum Anfassen, aber jeder darf hineinschauen.Und der Bonus:Jeder kann die Namen der zum Spielen berechtigten Personen mit Ihrem Geheimdienst haben.

private In der Tat...:-D

Die Lösung „Anonyme Namespaces“.

Anonyme Namespaces haben den Vorteil, dass sie die Dinge wirklich privat machen.

Zuerst der HPP-Header

// HPP

namespace Foo
{
   void barA() ;
}

Nur um sicherzugehen, dass Sie Folgendes bemerkt haben:Es gibt keine nutzlose Erklärung von barB oder myGlobal.Das 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 fooA und fooB wie bei der sogenannten „statischen Klassen“-Deklaration weiterhin auf myGlobal zugreifen.Aber niemand sonst kann es.Und niemand sonst außerhalb dieser CPP weiß, dass es fooB und myGlobal überhaupt gibt!

Im Gegensatz zur „statischen Klasse“, die nackt herumläuft und ihr Adressbuch auf die Haut tätowiert hat, ist der „anonyme“ Namensraum vollständig bekleidet, was AFAIK deutlich besser gekapselt zu sein scheint.

Ist es wirklich wichtig?

Es sei denn, die Benutzer Ihres Codes sind Saboteure (ich lasse Sie als Übung herausfinden, wie man mit einem schmutzigen, verhaltensundefinierten Hack auf den privaten Teil einer öffentlichen Klasse zugreifen kann ...), was ist das? private Ist private, auch wenn es im sichtbar ist private Abschnitt einer in einem Header deklarierten Klasse.

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

Bearbeiten 20.09.2014

Wann sind statische Klassenmethoden tatsächlich besser als Namespaces mit Nicht-Member-Funktionen?

Wenn Sie Funktionen gruppieren 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 Vorlagenparameter sein kann, ist dies bei einem Namespace nicht der Fall.

Sie können auch eine freie Funktion in einem Namespace 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.

Wenn Sie nach einer Möglichkeit suchen, das Schlüsselwort „static“ auf eine Klasse anzuwenden, wie Sie es beispielsweise in C# tun können

Statische Klassen sind lediglich der Compiler, der Sie an der Hand hält und Sie daran hindert, Instanzmethoden/-variablen zu schreiben.

Wenn Sie einfach eine normale Klasse ohne Instanzmethoden/-variablen schreiben, ist es dasselbe, und das ist, was Sie in C++ tun würden

In C++ möchten Sie eine statische Funktion einer Klasse erstellen (keine statische Klasse).

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

Sie sollten dann in der Lage sein, die Funktion mit BitParser::getBitAt() aufzurufen, ohne ein Objekt zu instanziieren, was meiner Meinung nach das gewünschte Ergebnis ist.

Kann ich so etwas schreiben? static class?

NEIN, entsprechend der C++11 N3337-Standardentwurf Anhang C 7.1.1:

Ändern:In C++ können die statischen oder externen Spezifizierer nur auf Namen von Objekten oder Funktionen angewendet werden.Die Verwendung dieser Spezifizierer mit Typdeklarationen ist in C++ illegal.In C werden diese Spezifizierer ignoriert, wenn sie bei Typdeklarationen verwendet werden.Beispiel:

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

Begründung:Speicherklassenspezifizierer haben keine Bedeutung, wenn sie einem Typ zugeordnet sind.In C ++ können Klassenmitglieder mit dem statischen Speicherklassenspezifizierer deklariert werden.Durch die Erlaubnis der Speicherklassenspezifizierer für Typdeklarationen kann der Code für Benutzer verwirrend sein.

Und wie struct, class ist auch eine Typdeklaration.

Das Gleiche kann durch Durchlaufen des Syntaxbaums in Anhang A abgeleitet werden.

Es ist interessant, das festzustellen static struct war in C legal, hatte aber keine Auswirkung: Warum und wann sollten statische Strukturen in der C-Programmierung verwendet werden?

Sie können in C++ eine statische Klasse haben, wie bereits erwähnt. Eine statische Klasse ist eine Klasse, für die keine Objekte instanziiert sind.In C++ kann dies erreicht werden, indem der Konstruktor/Destruktor als privat deklariert wird.Das Endergebnis ist das gleiche.

In Managed C++ lautet die Syntax statischer Klassen:

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

...besser spät als nie...

Dies ähnelt der Vorgehensweise von C# in C++

In C# file.cs können Sie eine private Variable innerhalb einer öffentlichen Funktion haben.Wenn Sie sich in einer anderen Datei befinden, können Sie es verwenden, indem Sie den Namespace mit der Funktion wie folgt aufrufen:

MyNamespace.Function(blah);

So implizieren Sie dasselbe in 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();

Im Gegensatz zu anderen verwalteten Programmiersprachen hat „statische Klasse“ in C++ KEINE Bedeutung.Sie können die statische Memberfunktion verwenden.

Wie hier bereits erwähnt, könnte die Verwendung von Namespaces eine bessere Möglichkeit sein, dies in C++ zu erreichen.Aber da hat das niemand erwähnt final Stichwort hier, ich poste, was ein direktes Äquivalent von ist static class von C# würde in C++11 oder höher so aussehen:

class BitParser final
{
public:
  BitParser() = delete;

  static bool GetBitAt(int buffer, int pos);
};

bool BitParser::GetBitAt(int buffer, int pos)
{
  // your code
}

Ein Fall, in dem Namespaces für die Erzielung „statischer Klassen“ möglicherweise nicht so nützlich sind, ist die Verwendung dieser Klassen zur Erzielung von Komposition statt Vererbung.Namespaces können keine Freunde von Klassen sein und daher nicht auf private Mitglieder einer Klasse zugreifen.

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;
  }
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top