300

C++ で静的クラスを作成するにはどうすればよいですか? 私は次のようなことができるはずです:

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

BitParser私がクラスを作成したと仮定します。BitParserクラス定義はどのようになりますか?

4

15 に答える 15

316

たとえば C# でできるように、"static" キーワードをクラスに適用する方法を探している場合は、Managed C++ を使用しないとできません。

しかし、サンプルの外観では、BitParser オブジェクトに public static メソッドを作成するだけです。そのようです:

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

このコードを使用して、サンプル コードと同じ方法でメソッドを呼び出すことができます。

于 2008-08-12T23:43:37.773 に答える
271

Matt Price のソリューションを考えてみましょう。

  1. C++ では、「静的クラス」には意味がありません。最も近いものは、静的メソッドとメンバーのみを持つクラスです。
  2. 静的メソッドを使用すると、制限されるだけです。

あなたが望むのは、C++ セマンティクスで表現された、関数 (関数であるため) を名前空間に配置することです。

2011 年 11 月 11 日を編集

C++ には「静的クラス」はありません。最も近い概念は、静的メソッドのみを持つクラスです。例えば:

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

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

ただし、「静的クラス」は Java に似た種類の言語 (C# など) のハックであり、非メンバー関数を持つことができないため、代わりにそれらを静的メソッドとしてクラス内に移動する必要があることを覚えておく必要があります。

C++ で本当に必要なのは、名前空間で宣言する非メンバー関数です。

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

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

何故ですか?

C++ では、名前空間は「Java 静的メソッド」パターンのクラスよりも強力です。その理由は次のとおりです。

  • 静的メソッドは、クラスのプライベート シンボルにアクセスできます
  • プライベートな静的メソッドは、(アクセスできない場合でも) すべてのユーザーに引き続き表示されます。これにより、カプセル化が多少破られます。
  • 静的メソッドは前方宣言できません
  • ライブラリ ヘッダーを変更せずにクラス ユーザーが静的メソッドをオーバーロードすることはできません。
  • 同じ名前空間の(おそらく友人の)非メンバー関数よりもうまく実行できない静的メソッドによって実行できることは何もありません
  • 名前空間には独自のセマンティクスがあります (組み合わせたり、匿名にしたりできます)。

結論: Java/C# のパターンを C++ にコピーして貼り付けないでください。Java/C# では、パターンは必須です。しかし、C++ ではスタイルが悪いです。

2010-06-10 を編集

静的プライベートメンバー変数を使用する必要がある場合があるため、静的メソッドを支持する議論がありました。

以下に示すように、私は多少同意しません。

「静的プライベートメンバー」ソリューション

// HPP

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

まず、myGlobal はグローバル プライベート変数であるため、myGlobal と呼ばれます。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 !!!
}

一見すると、無料の関数 barC が Foo::myGlobal にアクセスできないという事実は、カプセル化の観点からは良いことのように思えます... HPP を見ている誰かが (妨害行為に頼らない限り) アクセスできないため、クールです。 Foo::myGlobal.

しかし、よく見てみると、これは大きな間違いであることがわかります: プライベート変数を HPP で宣言する必要があるだけでなく (プライベートであるにもかかわらず、世界中から見えるようにする必要があります)、宣言する必要があります。同じHPPで、アクセスが許可されるすべての(すべての場合と同様に)機能!!!

したがって、プライベートな静的メンバーを使用することは、恋人のリストを皮膚に刺青して裸で外を歩くようなものです: 誰も触れることを許可されていませんが、誰もがのぞくことができます. そしておまけ: 誰もがあなたのプライベートで遊ぶことを許可された人の名前を持つことができます.

private確かに... :-D

「匿名名前空間」ソリューション

匿名の名前空間には、プライベートなものを本当にプライベートにするという利点があります。

まず、HPPヘッダー

// HPP

namespace Foo
{
   void barA() ;
}

念のため言っておきますが、barB や myGlobal の無駄な宣言はありません。つまり、ヘッダーを読んでいる人は、barA の背後に何が隠されているかを知りません。

次に、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 !!!
}

ご覧のとおり、いわゆる「静的クラス」宣言のように、fooA と fooB は引き続き myGlobal にアクセスできます。しかし、他の誰もできません。そして、この CPP 以外の誰も fooB と myGlobal の存在すら知りません!

アドレス帳を肌に刺青して裸で歩く「静的クラス」とは異なり、「匿名」名前空間は完全に服を着ており、カプセル化されているようです。

それは本当に問題ですか?

あなたのコードのユーザーが破壊工作員でない限り (演習として、ダーティ ビヘイビア未定義のハックを使用してパブリック クラスのプライベート部分にアクセスする方法を見つけてもらいます...)、たとえそれprivateがヘッダーで宣言されたクラスprivateのセクションに表示されます。private

それでも、プライベート メンバーにアクセスできる別の「プライベート関数」を追加する必要がある場合は、ヘッダーを変更して全世界に宣言する必要があります。これは、私に関する限りパラドックスです。私のコード (CPP 部分) の場合、インターフェイス (HPP 部分) は変更しないでください。レオニダスの言葉を引用: 「これはカプセル化です!

編集 2014-09-20

クラスの静的メソッドが実際に非メンバー関数を持つ名前空間よりも優れているのはいつですか?

関数をグループ化し、そのグループをテンプレートにフィードする必要がある場合:

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

クラスがテンプレート パラメーターになることができる場合、名前空間はできないためです。

于 2008-09-21T22:55:43.297 に答える
67

名前空間に無料の関数を作成することもできます。

BitParser.h 内

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

BitParser.cpp 内

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

一般に、これはコードを記述するための推奨される方法です。オブジェクトが必要ない場合は、クラスを使用しないでください。

于 2008-08-13T00:26:43.740 に答える
13

たとえばC#でできるように、「静的」キーワードをクラスに適用する方法を探している場合

静的クラスは、コンパイラーがあなたを手に入れ、インスタンスメソッド/変数を書くのを止めているだけです。

インスタンスメソッド/変数なしで通常のクラスを書くだけなら、それは同じことであり、これはC++で行うことです

于 2008-08-13T00:06:09.333 に答える
12

のようなものを書くことはできますstatic classか?

いいえC++11 N3337 標準ドラフトAnnex C 7.1.1 によると:

変更: C ++ では、static または extern 指定子は、オブジェクトまたは関数の名前にのみ適用できます。これらの指定子を型宣言で使用することは、C++ では違法です。C では、型宣言でこれらの指定子を使用すると無視されます。例:

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

理論的根拠: ストレージ クラス指定子は、型に関連付けられている場合は意味がありません。C++ では、静的ストレージ クラス指定子を使用してクラス メンバーを宣言できます。型宣言でストレージ クラス指定子を許可すると、コードがユーザーにとって混乱を招く可能性があります。

と同様structclassも型宣言です。

同じことは、付録 A の構文ツリーをたどることによって推測できます。

static structC では合法でしたが、効果がなかったことに注目するのは興味深いことです。なぜ、いつ C プログラミングで静的構造を使用するのですか?

于 2015-07-03T08:22:19.150 に答える
11

C++ では、クラス (静的クラスではない) の静的関数を作成する必要があります。

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

その後、BitParser::getBitAt() を使用して、目的の結果であると思われるオブジェクトをインスタンス化せずに関数を呼び出すことができるはずです。

于 2008-08-12T23:43:34.840 に答える
5

前述のように、C++ で静的クラスを持つことができます。静的クラスは、インスタンス化されたオブジェクトを持たないクラスです。C++ では、コンストラクター/デストラクターをプライベートとして宣言することで取得できます。最終結果は同じです。

于 2009-11-23T21:04:27.420 に答える
4

Managed C ++では、静的クラスの構文は次のとおりです。

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

...決して遅くなるよりはまし...

于 2010-06-10T15:35:29.317 に答える
3

これは、C++ で行う C# の方法に似ています。

C# file.cs では、パブリック関数内にプライベート var を含めることができます。別のファイルにある場合は、次のように関数で名前空間を呼び出すことで使用できます。

MyNamespace.Function(blah);

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

その他のファイル.h

#include "SharedModule.h"

その他のファイル.cpp

//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();
于 2010-04-26T18:44:39.230 に答える
2

(多くの) 代替案の 1 つですが、(私の意見では) 最も洗練された (静的な動作をエミュレートするために名前空間とプライベート コンストラクターを使用する場合と比較して)、C++ で「インスタンス化できないクラス」の動作を実現する方法は、privateアクセス修飾子を使用して、ダミーの純粋仮想関数を宣言します。

class Foo {
   public:
     static int someMethod(int someArg);

   private:
     virtual void __dummy() = 0;
};

finalC++11 を使用している場合は、クラス宣言で指定子を使用して他のクラスがそれを継承しないように制限することで、クラスが継承されないようにする (純粋に静的クラスの動作をエミュレートする) ために、さらに一歩進むことができます。.

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
      virtual void __dummy() = 0;
};

ばかばかしく非論理的に聞こえるかもしれませんが、C++11 では「オーバーライドできない純粋仮想関数」の宣言が可能です。これをクラスの宣言と一緒に使用してfinal、静的動作を純粋かつ完全に実装すると、結果として結果が得られます。クラスは継承できず、ダミー関数はいかなる方法でもオーバーライドされません。

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
     // Other private declarations

     virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class
于 2020-05-06T01:52:19.243 に答える
0
class A final {
  ~A() = delete;
  static bool your_func();
}

finalクラスを継承できないことを意味します。

deleteデストラクタの場合、そのようなクラスのインスタンスを作成できないことを意味します。

このパターンは「util」クラスとしても知られています。

多くの人が言うように、の概念はstatic classC++ には存在しません。

この場合のソリューションとして優先される機能namespaceを含む標準。static

于 2021-03-01T12:53:56.933 に答える
0

「静的クラス」を実現するのに名前空間があまり役に立たないケースの 1 つは、これらのクラスを使用して継承による構成を実現する場合です。名前空間はクラスのフレンドになることはできないため、クラスのプライベート メンバーにアクセスすることはできません。

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;
  }
};
于 2018-04-25T07:47:11.330 に答える