C++ で静的クラスを作成するにはどうすればよいですか?
質問
C++ で静的クラスを作成するにはどうすればよいですか?次のようなことができるはずです:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
私が作成したと仮定すると、 BitParser
クラス。どうなるでしょうか BitParser
クラス定義は次のようになりますか?
解決
たとえば C# のように、クラスに "static" キーワードを適用する方法を探している場合は、マネージ C++ を使用しないと実行できません。
ただし、サンプルの外観では、BitParser オブジェクトにパブリック静的メソッドを作成するだけで済みます。そのようです:
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;
}
このコードを使用して、サンプル コードと同じ方法でメソッドを呼び出すことができます。
お役に立てば幸いです!乾杯。
他のヒント
考慮する マット・プライスの解決策.
- C++ では、「静的クラス」は意味を持ちません。最も近いものは、静的メソッドとメンバーのみを含むクラスです。
- 静的メソッドを使用しても制限がかかるだけです。
あなたが望むのは、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 内で宣言する必要がある (つまり、プライベートであるにもかかわらず、世界中のユーザーが参照できる) だけでなく、その変数へのアクセスを許可されるすべての関数 (ALL と同様) を同じ 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 !!!
クラスがテンプレート パラメーターになれる場合でも、名前空間はテンプレート パラメーターにできないためです。
名前空間に無料の関数を作成することもできます。
BitParser.h 内
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
BitParser.cpp 内
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
一般に、これはコードを記述するための推奨される方法です。オブジェクトが必要ない場合は、クラスを使用しないでください。
たとえば C# のように、「static」キーワードをクラスに適用する方法を探している場合
静的クラスは、コンパイラの役割を担っており、インスタンス メソッドや変数の作成を阻止します。
インスタンス メソッドや変数を使用せずに通常のクラスを作成した場合も同じであり、これが C++ で行うことです。
C++ では、(静的クラスではなく) クラスの静的関数を作成したいとします。
class BitParser {
public:
...
static ... getBitAt(...) {
}
};
そうすれば、オブジェクトをインスタンス化せずに BitParser::getBitAt() を使用して関数を呼び出すことができるはずです。これが望ましい結果であると思われます。
次のようなことを書いてもいいですか static class
?
いいえ, 、 による C++11 N3337 標準ドラフト 付録 C 7.1.1:
変化:C++ では、static 指定子または extern 指定子は、オブジェクトまたは関数の名前にのみ適用できます。型宣言でこれらの指定子を使用することは、C++ では違法です。Cでは、タイプ宣言で使用すると、これらの指定器は無視されます。例:
static struct S { // valid C, invalid in C++ int i; };
理論的根拠:ストレージ クラス指定子は、型に関連付けられている場合は意味を持ちません。C ++では、クラスメンバーは静的ストレージクラス指定器で宣言できます。タイプ宣言でストレージクラスの仕様を許可すると、ユーザーにとってコードが混乱する可能性があります。
そして、好き struct
, class
も型宣言です。
同じことは、付録 A の構文ツリーをたどることでも推測できます。
興味深いのは、 static struct
C では正当ですが、効果はありませんでした。 C プログラミングで静的構造体を使用する理由とタイミングは何ですか?
前述したように、C++ では静的クラスを持つことができます。静的クラスとは、インスタンス化されたオブジェクトを持たないクラスのことです。C++ では、これはコンストラクター/デストラクターをプライベートとして宣言することで取得できます。最終結果は同じです。
マネージド C++ では、静的クラスの構文は次のとおりです。
public ref class BitParser abstract sealed
{
public:
static bool GetBitAt(...)
{
...
}
}
...遅刻しないよりはマシだ...
これは、C++ で C# を実行する方法に似ています。
C# file.cs では、パブリック関数内にプライベート変数を含めることができます。別のファイルにある場合は、次のように関数を使用して名前空間を呼び出すことでそれを使用できます。
MyNamespace.Function(blah);
C++ で同じことを imp する方法は次のとおりです。
SharedModule.h
class TheDataToBeHidden
{
public:
static int _var1;
static int _var2;
};
namespace SharedData
{
void SetError(const char *Message, const char *Title);
void DisplayError(void);
}
共有モジュール.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();
他のマネージ プログラミング言語とは異なり、C++ では「静的クラス」は意味を持ちません。静的メンバー関数を利用することができます。
ここで述べたように、C++ でこれを実現するより良い方法は、名前空間を使用することかもしれません。しかし誰も言及していないので、 final
ここでのキーワード、私はこれに直接相当するものを投稿しています static class
C# からの場合、C++11 以降では次のようになります。
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
「静的クラス」を実現するために名前空間があまり役に立たないケースの 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;
}
};