Come si crea una class statica in C ++?

Come si crea una class statica in C ++? Dovrei essere in grado di fare qualcosa come:

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

Supponendo che ho creato la class BitParser . Come sarebbe la definizione della class BitParser ?

Se stai cercando un modo per applicare la parola chiave “statica” a una class, ad esempio in C #, non potrai utilizzare senza Managed C ++.

Ma l’aspetto del tuo campione, devi solo creare un metodo statico pubblico sul tuo object BitParser. Così:

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

È ansible utilizzare questo codice per chiamare il metodo nello stesso modo del codice di esempio.

Spero possa aiutare! Saluti.

Considera la soluzione di Matt Price .

  1. In C ++, una “class statica” non ha significato. La cosa più vicina è una class con solo metodi e membri statici.
  2. L’utilizzo di metodi statici limiterà solo te.

Quello che vuoi è, express in semantica C ++, mettere la tua funzione (perché è una funzione) in un namespace.

Modifica 2011-11-11

Non esiste una “class statica” in C ++. Il concetto più vicino sarebbe una class con solo metodi statici. Per esempio:

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

Ma è necessario ricordare che le “classi statiche” sono hack in linguaggi simili a Java (ad esempio C #) che non sono in grado di avere funzioni non membro, quindi devono invece spostarle all’interno delle classi come metodi statici.

In C ++, quello che vuoi veramente è una funzione non membro che dichiarerai in un namespace:

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

Perché?

In C ++, lo spazio dei nomi è più potente delle classi per il modello “metodo statico Java”, in quanto:

  • i metodi statici hanno accesso ai simboli private delle classi
  • i metodi statici privati ​​sono ancora visibili (se inaccessibili) a tutti, il che viola in qualche modo l’incapsulamento
  • i metodi statici non possono essere inoltrati
  • i metodi statici non possono essere sovraccaricati dall’utente della class senza modificare l’intestazione della libreria
  • non c’è nulla che possa essere fatto con un metodo statico che non può essere fatto meglio di una funzione non membro (possibilmente amico) nello stesso spazio dei nomi
  • gli spazi dei nomi hanno la loro semantica (possono essere combinati, possono essere anonimi, ecc.)
  • eccetera.

Conclusione: non copiare / incollare il modello di Java / C # in C ++. In Java / C #, il modello è obbligatorio. Ma in C ++, è cattivo stile.

Modifica 2010-06-10

C’è stato un argomento a favore del metodo statico, perché a volte è necessario utilizzare una variabile membro privata statica.

Non sono d’accordo, come mostrato di seguito:

La soluzione “membro statico privato”

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

Innanzitutto, myGlobal è chiamato myGlobal perché è ancora una variabile privata globale. Uno sguardo alla fonte CPP chiarirà che:

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

A prima vista, il fatto che la funzione libera barC non possa accedere a Foo :: myGlobal sembra una cosa buona da un punto di vista di incapsulamento … È bello perché qualcuno che guarda l’HPP non sarà in grado (a meno di ricorrere al sabotaggio) per accedere foo :: myglobal.

Ma se lo guardi da vicino, scoprirai che si tratta di un errore colossale: non solo la tua variabile privata deve essere ancora dichiarata nell’HPP (e così, visibile a tutto il mondo, nonostante sia privata), ma devi dichiarare nello stesso HPP tutte (come in TUTTE) le funzioni che saranno autorizzate ad accedervi !!!

Quindi usare un membro statico privato è come camminare fuori nel nudo con la lista dei tuoi amanti tatuati sulla tua pelle: nessuno è autorizzato a toccare, ma tutti sono in grado di sbirciare. E il bonus: tutti possono avere i nomi di quelli autorizzati a giocare con i tuoi privies.

private effetti anzi … MrGreen

La soluzione “namespace anonimi”

Gli spazi dei nomi anonimi avranno il vantaggio di rendere le cose private davvero private.

Innanzitutto, l’intestazione HPP

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

Solo per essere sicuri che tu abbia osservato: non ci sono dichiarazioni inutili di barB né myGlobal. Il che significa che nessuno che legge l’intestazione sa cosa è nascosto dietro la barra.

Quindi, il 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 !!! } 

Come puoi vedere, come la cosiddetta dichiarazione della “class statica”, fooA e fooB sono ancora in grado di accedere a myGlobal. Ma nessun altro può. E nessun altro al di fuori di questo CPP sa che fooB e myGlobal esistono addirittura!

A differenza della “class statica” che cammina sul nudo con la sua rubrica tatuata sulla sua pelle, lo spazio dei nomi “anonimo” è completamente rivestito , che sembra AFAIK meglio incapsulato.

Importa davvero?

A meno che gli utenti del tuo codice non siano sabotatori (ti consentirò, come esercizio, di scoprire come accedere alla parte privata di una class pubblica usando un comportamento sporco – hack indefinito …), ciò che è private è private , persino se è visibile nella sezione private di una class dichiarata in un’intestazione.

Tuttavia, se è necessario aggiungere un’altra “funzione privata” con accesso al membro privato, è comunque necessario dichiararlo a tutto il mondo modificando l’intestazione, che per quanto mi riguarda è un paradosso: se cambio l’implementazione di il mio codice (la parte CPP), quindi l’interfaccia (la parte HPP) NON deve cambiare. Citando Leonida: ” Questa è INCAPSULAMENTO!

Modifica 2014-09-20

Quando sono le classi i metodi statici sono effettivamente migliori degli spazi dei nomi con funzioni non membri?

Quando è necessario raggruppare le funzioni e alimentare quel gruppo a un modello:

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

Perché se una class può essere un parametro di modello, gli spazi dei nomi non possono.

Puoi anche creare una funzione gratuita in uno spazio dei nomi:

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 :) } } 

In generale questo sarebbe il modo preferito per scrivere il codice. Quando non c’è bisogno di un object non usare una class.

Se stai cercando un modo per applicare la parola chiave “statica” ad una class, ad esempio puoi farlo in C #

le classi statiche sono solo il compilatore che ti tiene in mano e ti impedisce di scrivere qualsiasi metodo / variabile di istanza.

Se scrivi semplicemente una class normale senza alcun metodo / variabile di istanza, è la stessa cosa, e questo è ciò che dovresti fare in C ++

In C ++ si desidera creare una funzione statica di una class (non una class statica).

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

Dovresti quindi essere in grado di chiamare la funzione utilizzando BitParser :: getBitAt () senza creare un’istanza di un object che presumo sia il risultato desiderato.

Posso scrivere qualcosa come static class ?

No , secondo la bozza standard C33 11 N3337 allegato C 7.1.1:

Modifica: in C ++, gli specificatori statici o extern possono essere applicati solo ai nomi di oggetti o funzioni. L’uso di questi specificatori con dichiarazioni di tipo è illegale in C ++. In C, questi specificatori vengono ignorati quando vengono utilizzati nelle dichiarazioni di tipo. Esempio:

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

Motivazione: gli specificatori della class di archiviazione non hanno alcun significato se associati a un tipo. In C ++, i membri della class possono essere dichiarati con lo specificatore della class di archiviazione statica. Permettendo che gli identificatori delle classi di memoria sulle dichiarazioni di tipo potrebbero rendere il codice confuso per gli utenti.

E come struct , anche la class è una dichiarazione di tipo.

Lo stesso può essere dedotto percorrendo l’albero della syntax nell’Allegato A.

È interessante notare che static struct era legale in C, ma non aveva alcun effetto: perché e quando utilizzare le strutture statiche nella programmazione in C?

Si puo ‘avere una class statica in C ++, come accennato prima, una class statica è una class che non ha alcun object di essa istanziato. In C ++, questo può essere ottenuto dichiarando il costruttore / distruttore come privato. Il risultato finale è lo stesso.

In Managed C ++, la syntax della class statica è: –

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

… meglio tardi che mai…

Questo è simile al modo in C # di farlo in C ++

In C # file.cs è ansible avere private var all’interno di una funzione pubblica. Quando in un altro file puoi usarlo chiamando lo spazio dei nomi con la funzione come in:

 MyNamespace.Function(blah); 

Ecco come imp ina lo stesso 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(); 

A differenza di altri linguaggi di programmazione gestiti, la “class statica” NON ha significato in C ++. È ansible utilizzare la funzione membro statico.

Come è stato notato qui, un modo migliore per ottenere questo in C ++ potrebbe essere l’uso di namespace. Ma dal momento che nessuno ha menzionato la parola chiave final qui, sto postando quale sarebbe l’equivalente diretto della static class da C # in C ++ 11 o versioni successive:

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

Un caso in cui gli spazi dei nomi potrebbero non essere così utili per ottenere “classi statiche” è quando si utilizzano queste classi per ottenere la composizione sull’ereditarietà. I namespace non possono essere amici di classi e quindi non possono accedere ai membri privati ​​di una class.

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