Jak stworzyć statyczną klasę w C++?

Jak stworzyć statyczną klasę w C++? Powinienem być w stanie zrobić coś takiego:

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

Zakładając, że stworzyłem BitParser klasę. Jak wyglądałaby definicja klasy BitParser?

Author: Onur A., 2008-08-13

12 answers

Jeśli szukasz sposobu na zastosowanie słowa kluczowego "static" do klasy, jak na przykład w C#, nie będziesz w stanie tego zrobić bez użycia Managed C++.

Ale wygląd próbki, wystarczy utworzyć publiczną statyczną metodę na obiekcie BitParser. TAK:

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

Możesz użyć tego kodu do wywołania metody w taki sam sposób jak przykładowy kod.

Mam nadzieję, że to pomoże! Zdrowie.
 233
Author: OJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 17:32:02

Rozważmy rozwiązanie Matta Price ' a .

  1. W C++ "Klasa statyczna" nie ma znaczenia. Najbliższą rzeczą jest klasa z tylko statycznymi metodami i członkami.
  2. używanie metod statycznych tylko cię ograniczy.

To, co chcesz, to, wyrażona w semantyce C++, umieścić swoją funkcję (dla niej jest funkcją) w przestrzeni nazw.

Edytuj 2011-11-11

Nie ma "klasy statycznej" w C++. Najbliższa koncepcja to klasa z tylko metody statyczne. Na przykład:

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

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

Ale musisz pamiętać, że "klasy statyczne" to hacki w językach podobnych do Javy (np. C#), które nie mogą mieć funkcji nie-członkowskich, więc zamiast tego muszą przenosić je wewnątrz klas jako metody statyczne.

W C++, to czego naprawdę chcesz to funkcja nie-członkowska, którą zadeklarujesz w przestrzeni nazw:

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

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

W C++ przestrzeń nazw jest potężniejsza niż klasy " Java static method" wzór, ponieważ:

  • statyczne metody mają dostęp do klas prywatnych symboli
  • Prywatne metody statyczne są nadal widoczne (jeśli są niedostępne) dla wszystkich, co narusza nieco enkapsulację]}
  • metody statyczne nie mogą być deklarowane w przyszłości
  • statyczne metody nie mogą być przeciążone przez użytkownika klasy bez modyfikacji nagłówka biblioteki
  • nie ma nic, co można zrobić metodą statyczną, której nie można zrobić lepiej niż (ewentualnie przyjaciel) funkcja non-member w tej samej przestrzeni nazw
  • przestrzenie nazw mają swoją własną semantykę (mogą być łączone, mogą być anonimowe, itp.)
  • itd.

Wniosek: nie kopiuj/wklej wzorca Java / C#w C++. W Javie/C# wzorzec jest obowiązkowy. Ale w C++ jest to zły styl.

Edycja 2010-06-10

Był argument na korzyść metody statycznej, ponieważ czasami trzeba użyć statycznej zmiennej prywatnej.

Nie zgadzam się nieco, jak pokazano poniżej:

Rozwiązanie "static private member"]}
// HPP

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

Po pierwsze, myGlobal nazywa się myGlobal, ponieważ nadal jest globalną zmienną prywatną. W 1999 roku, po raz pierwszy w historii CPP, pojawiła się nowa wersja CPP.]}

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

Na pierwszy rzut oka, fakt, że wolna funkcja barC nie może uzyskać dostępu do Foo::myGlobal wydaje się dobrą rzeczą z punktu widzenia enkapsulacji... Fajnie, bo ktoś patrzący na HPP nie będzie mógł (chyba że ucieknie się do sabotażu) uzyskać dostępu Foo:: myGlobal.

Ale jeśli przyjrzysz się temu uważnie, zauważysz, że jest to kolosalny błąd: nie tylko twoja prywatna zmienna musi być nadal zadeklarowana w HPP (a więc widoczna dla całego świata, mimo że jest prywatna), ale musisz zadeklarować w tym samym HPP Wszystkie (jak we wszystkich) funkcje, które będą upoważnione do dostępu do niej !!!

Więc używanie prywatnego członka statycznego jest jak chodzenie na zewnątrz nago z listą Twoich kochanków wytatuowaną na twojej skórze: nikt nie jest upoważniony do dotyk, ale każdy jest w stanie zerknąć. I bonus: każdy może mieć nazwiska osób upoważnionych do gry z privies.

private W rzeczy samej... :- D

Jest to rozwiązanie typu "Anonymous namespaces" (anonimowe przestrzenie nazw).]}

Anonimowe przestrzenie nazw będą miały tę zaletę, że uczynią rzeczy prywatnymi naprawdę prywatnymi.

Najpierw nagłówek HPP

// HPP

namespace Foo
{
   void barA() ;
}

Dla pewności zauważyłeś: nie ma bezużytecznej deklaracji barB ani myGlobal. Co oznacza, że nikt nie czyta nagłówka wie, co kryje się za barą.

Następnie 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 !!!
}

Jak widzisz, podobnie jak tzw. deklaracja "klasy statycznej", fooA i fooB nadal mają dostęp do myGlobal. Ale nikt inny nie może. I nikt poza tym CPP nie wie, że fooB i myGlobal nawet istnieją!

W przeciwieństwie do" klasy statycznej "chodzącej nago z wytatuowaną książką adresową na skórze, przestrzeń nazw" anonymous " jest w pełni ubrana {71]}, co wydaje się całkiem lepiej zamknięte AFAIK.

Czy to ma znaczenie?

Chyba, że użytkownicy Twojego kodu są sabotażystami (pozwolę ci, jako ćwiczenie, dowiedzieć się, jak można uzyskać dostęp do prywatnej części klasy publicznej za pomocą brudnego hacka-niezdefiniowanego zachowania...), co private jest private, nawet jeśli jest widoczne w sekcji private klasy zadeklarowanej w nagłówku.

Mimo to, jeśli chcesz dodać kolejną "prywatną funkcję" z dostępem do prywatnego członka, nadal musisz zadeklarować ją całemu światu, modyfikując header, co jest paradoksem jeśli O mnie chodzi: jeśli zmienię implementację mojego kodu (część CPP), to interfejs (część HPP) nie powinien się zmieniać.To jest enkapsulacja!"

Edycja 2014-09-20

Kiedy statyczne metody klas są lepsze niż przestrzenie nazw z funkcjami nieczłonkowymi?

Kiedy trzeba pogrupować funkcje i przekazać tę grupę do szablonu:

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

Ponieważ, jeśli Klasa może być parametrem szablonu, przestrzenie nazw nie mogą.

 213
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-05 12:48:43

Możesz również utworzyć wolną funkcję w przestrzeni nazw:

W Bitparserze.h

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

W Bitparserze.cpp

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

Ogólnie jest to preferowany sposób napisania kodu. Gdy obiekt nie jest potrzebny, nie używaj klasy.

 58
Author: Matt Price,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-13 00:26:43

Jeśli szukasz sposobu na zastosowanie słowa kluczowego "static" do klasy, jak na przykład w C#

Klasy statyczne są tylko ręcznym kompilatorem-trzymającym cię i powstrzymującym przed pisaniem jakichkolwiek metod/zmiennych instancji.

Jeśli po prostu piszesz normalną klasę bez żadnych metod/zmiennych instancji, to jest to samo, a to jest to, co robisz w C++

 12
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-13 00:06:09

W C++ chcesz utworzyć statyczną funkcję klasy (nie statyczną klasę).

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

Powinieneś być w stanie wywołać funkcję za pomocą metody BitParser:: getBitAt() bez tworzenia instancji obiektu, który, jak przypuszczam, jest pożądanym rezultatem.

 11
Author: Philip Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-12 23:43:34

Czy mogę napisać coś w stylu static class?

Nie , zgodnie z C++11 n3337 standard draft Załącznik C 7.1.1:

Zmiana: w C ++ statyczne lub zewnętrzne specyfikatory mogą być stosowane tylko do nazw obiektów lub funkcji. Używanie tych specyfikatorów z deklaracjami typu jest nielegalne w C ++. W języku C te specyfikatory są ignorowane, gdy są używane na deklaracjach typu. Przykład:

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

Uzasadnienie: storage class specifiers don ' t have any meaning w przypadku powiązania z typem. W C ++, Klasa pręty mogą być zadeklarowane za pomocą statycznego specyfikatora klasy storage. Możliwość określenia klasy pamięci masowej na typ deklaracje mogą sprawić, że kod będzie mylący dla użytkowników.

I jak struct, class jest również deklaracją typu.

To samo można wywnioskować przechodząc przez drzewo składni w Załączniku A.

Warto zauważyć, że static struct było legalne w C, ale nie miało żadnego wpływu: dlaczego i kiedy używać statycznych struktur w C programowanie?

 10
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 08:37:50

Możesz mieć klasę statyczną w C++, jak wspomniano wcześniej, Klasa statyczna to taka, która nie ma żadnych obiektów z jej instancji. W C++ można to uzyskać, deklarując konstruktor/Destruktor jako prywatny. Efekt końcowy jest taki sam.

 5
Author: Netzer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-23 21:04:27

W Managed C++ statyczna składnia klasy to: -

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

... lepiej późno niż wcale...

 4
Author: Malc B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-10 15:35:29

Jest to podobne do sposobu wykonywania tego w C # w C++

W pliku C#.cs możesz mieć prywatny var wewnątrz publicznej funkcji. Gdy w innym pliku możesz go użyć, wywołując przestrzeń nazw z funkcją jak w:

MyNamespace.Function(blah);

Oto Jak zaimponować to samo w 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();
 3
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-27 02:38:36

W przeciwieństwie do innych zarządzanych języków programowania, "Klasa statyczna" nie ma znaczenia w C++. Możesz skorzystać ze statycznej funkcji członka.

 3
Author: Bharath Ravindra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-29 06:34:41

Jak zostało to tutaj zauważone, lepszym sposobem osiągnięcia tego w C++ może być użycie przestrzeni nazw. Ale ponieważ nikt nie wspomniał tutaj o słowie kluczowym final, zamieszczam jak bezpośredni odpowiednik {[2] } Z C# wyglądałby w C++11 lub później:

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

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

bool BitParser::GetBitAt(int buffer, int pos)
{
  // your code
}
 1
Author: Mikhail Vasilyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 11:52:10

Jednym z przypadków, w którym przestrzenie nazw mogą nie być tak przydatne do osiągnięcia "klas statycznych", jest użycie tych klas do osiągnięcia kompozycji ponad dziedziczenie. Przestrzenie nazw nie mogą być znajomymi klas, a więc nie mogą uzyskać dostępu do prywatnych członków klasy.

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;
  }
};
 0
Author: Josh Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 07:47:11