Domanda

Come si crea una classe statica in C++?Dovrei essere in grado di fare qualcosa del tipo:

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

Supponendo che io abbia creato il file BitParser classe.Cosa sarebbe il BitParser assomiglia alla definizione della classe?

È stato utile?

Soluzione

Se stai cercando un modo per applicare la parola chiave "statica" a una classe, come puoi fare ad esempio in C#, non potrai farlo senza utilizzare Managed C++.

Ma a giudicare dall'aspetto del tuo esempio, devi solo creare un metodo statico pubblico sul tuo oggetto 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;
}

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

Spero che aiuti!Saluti.

Altri suggerimenti

Prendere in considerazione La soluzione di Matt Price.

  1. In C++, una "classe statica" non ha significato.La cosa più vicina è una classe con solo metodi e membri statici.
  2. L'uso di metodi statici ti limiterà solo.

Quello che vuoi è, espresso nella semantica C++, mettere la tua funzione (per esso È una funzione) in uno spazio dei nomi.

Modifica 2011-11-11

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

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

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

Ma devi ricordare che le "classi statiche" sono hack nei linguaggi simili a Java (ad es.C#) che non possono avere funzioni non membro, quindi devono spostarle all'interno delle classi come metodi statici.

In C++, ciò che vuoi veramente è una funzione non membro che dichiarerai in uno spazio dei nomi:

// 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", perché:

  • i metodi statici hanno accesso ai simboli privati ​​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 dichiarati in avanti
  • i metodi statici non possono essere sovraccaricati dall'utente della classe senza modificare l'intestazione della libreria
  • non c'è nulla che possa essere fatto con un metodo statico che non possa essere fatto meglio di una funzione non membro (possibilmente amica) nello stesso spazio dei nomi
  • gli spazi dei nomi hanno una propria semantica (possono essere combinati, possono essere anonimi, ecc.)
  • eccetera.

Conclusione:Non copiare/incollare il modello Java/C# in C++.In Java/C#, il modello è obbligatorio.Ma in C++ è uno stile pessimo.

Modifica 2010-06-10

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

Non sono d'accordo in qualche modo, come mostrato di seguito:

La soluzione "Membro privato statico".

// HPP

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

Innanzitutto, myGlobal si chiama 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 gratuita barC non possa accedere a Foo::myGlobal sembra una buona cosa dal punto di vista dell'incapsulamento...È bello perché qualcuno che guarda l'HPP non sarà in grado (a meno che non ricorra al sabotaggio) di accedere a Foo::myGlobal.

Ma se lo guardi da vicino, scoprirai che è un errore colossale:Non solo la tua variabile privata deve essere ancora dichiarata nell'HPP (e quindi 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! !!

COSÌ usare un membro statico privato è come uscire nudo con l'elenco dei tuoi amanti tatuato sulla pelle:Nessuno è autorizzato a toccare, ma tutti possono sbirciare.E il bonus:Tutti possono avere i nomi delle persone autorizzate a giocare con i tuoi gabinetti.

private Infatti...:-D

La soluzione "Spazi dei nomi 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() ;
}

Giusto per essere sicuro che tu abbia osservato:Non esiste alcuna dichiarazione inutile di barB né myGlobal.Ciò significa che nessuno che legge l'intestazione sa cosa si nasconde dietro barA.

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 di "classe statica", fooA e fooB sono ancora in grado di accedere a myGlobal.Ma nessun altro può farlo.E nessun altro al di fuori di questo CPP sa che fooB e myGlobal esistono!

A differenza della "classe statica" che cammina nuda con la sua rubrica tatuata sulla pelle, lo spazio dei nomi "anonimo" è completamente vestito, che sembra incapsulato molto meglio AFAIK.

Importa davvero?

A meno che gli utenti del tuo codice non siano sabotatori (ti lascerò, come esercizio, scoprire come si può accedere alla parte privata di una classe pubblica usando un hack sporco dal comportamento indefinito...), cosa succede private È private, anche se è visibile nel private sezione di una classe dichiarata in un'intestazione.

Tuttavia, se devi aggiungere un'altra "funzione privata" con accesso al membro privato, devi comunque dichiararla a tutto il mondo modificando l'intestazione, il che per me è un paradosso: Se cambio l'implementazione del mio codice (la parte CPP), l'interfaccia (la parte HPP) NON dovrebbe cambiare. Citando Leonida:"Questo è INCAPSULAMENTO!"

Modifica 20/09/2014

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

Quando è necessario raggruppare insieme funzioni e alimentare quel gruppo in un modello:

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

Perché, se una classe può essere un parametro di modello, uno spazio dei nomi non può.

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

In BitParser.h

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

Nel file 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 è necessario un oggetto, non utilizzare una classe.

Se stai cercando un modo per applicare la parola chiave "statica" a una classe, come puoi fare ad esempio in C#

le classi statiche sono solo il compilatore che ti tiene per mano e ti impedisce di scrivere metodi/variabili di istanza.

Se scrivi semplicemente una classe normale senza metodi/variabili di istanza, è la stessa cosa, e questo è ciò che faresti in C++

In C++ vuoi creare una funzione statica di una classe (non una classe statica).

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

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

Posso scrivere qualcosa del genere static class?

NO, secondo il Bozza standard C++11 N3337 Allegato C 7.1.1:

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

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

Fondamento logico:Gli identificatori della classe di archiviazione non hanno alcun significato se associati a un tipo.In C ++, i membri della classe possono essere dichiarati con lo specificatore della classe di archiviazione statica.Consentire gli specificatori della classe di archiviazione sulle dichiarazioni dei tipi potrebbe rendere il codice confuso per gli utenti.

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

Lo stesso può essere dedotto percorrendo l'albero della sintassi nell'Allegato A.

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

È possibile avere una classe statica in C++, come accennato in precedenza, una classe statica è quella che non ha alcun oggetto istanziato.In C++, ciò può essere ottenuto dichiarando privato il costruttore/distruttore.Il risultato finale è lo stesso.

In Managed C++, la sintassi della classe statica è: -

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

...meglio tardi che mai...

Questo è simile al modo in cui C# lo fa in C++

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

MyNamespace.Function(blah);

Ecco come eseguire 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);
}

ModuloCondiviso.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
  }
}

AltroFile.h

#include "SharedModule.h"

AltroFile.cpp

//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();

A differenza di altri linguaggi di programmazione gestiti, la "classe statica" NON ha alcun significato in C++.È possibile utilizzare la funzione membro statica.

Come è stato notato qui, un modo migliore per raggiungere questo obiettivo in C++ potrebbe essere l'utilizzo degli spazi dei nomi.Ma poiché nessuno ha menzionato il final parola chiave qui, sto pubblicando l'equivalente diretto di static class da C# sarebbe simile a C++11 o successivo:

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 tramite ereditarietà.Gli spazi dei nomi non possono essere amici delle classi e quindi non possono accedere ai membri privati ​​di una 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;
  }
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top