C ++で静的クラスをどのように作成しますか?私は次のようなことができるはずです:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
BitParser
クラスを作成したと仮定します。何だろうBitParser
ようなクラス定義を見て?
C ++で静的クラスをどのように作成しますか?私は次のようなことができるはずです:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
BitParser
クラスを作成したと仮定します。何だろうBitParser
ようなクラス定義を見て?
回答:
たとえばC#でできるように、クラスに「静的」キーワードを適用する方法を探している場合は、マネージ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;
}
このコードを使用して、サンプルコードと同じ方法でメソッドを呼び出すことができます。
お役に立てば幸いです。乾杯。
private: BitParser() {}
これにより、誰もインスタンスを作成できなくなります。
BitParser() = delete;
、コンストラクターを削除する意図を(それをとして非表示にするだけでなくprivate
)適切に伝える方がよいと主張します。
Matt Priceのソリューションを考えてみましょう。
必要なのは、C ++セマンティクスで表され、名前空間に関数(関数であるため)を配置することです。
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静的メソッド」パターンのクラスよりも強力です。
結論:C ++でそのJava / C#のパターンをコピー/貼り付けしないでください。Java / C#では、パターンは必須です。しかし、C ++では、それは悪いスタイルです。
静的なプライベートメンバー変数を使用する必要がある場合があるため、静的メソッドを支持する議論がありました。
以下に示すように、私は多少同意しません。
// 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内で(ALLと同様に)すべての機能にアクセスすることが許可されます!!!
つまり、プライベートスタティックメンバーを使用することは、恋人のリストが皮膚に刺青された状態でヌードの外を歩くようなものです。誰も触れることは許可されていませんが、誰でも覗くことができます。そしてボーナス:誰もがあなたのプリビと遊ぶことを許可された人の名前を持つことができます。
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が存在することさえ知りません!
彼女のアドレス帳が彼女の肌に刺青された状態でヌードの上を歩く「静的クラス」とは異なり、「匿名の」名前空間は完全に覆われ、これはAFAIKをかなりカプセル化したようです。
あなたのコードのユーザーが工作員でない限り(私は...あなたは、練習として、1が汚い行動未定義ハックを使用して、パブリッククラスのプライベートの部分にアクセスする方法を見つけるもらおう)、何してprivate
いるprivate
としても、それならば、private
ヘッダーで宣言されたクラスのセクションに表示されます。
それでも、プライベートメンバーへのアクセス権を持つ別の「プライベート関数」を追加する必要がある場合でも、ヘッダーを変更することによってそれを全世界に宣言する必要があります。これは、私に関する限りパラドックスです:の実装を変更した場合私のコード(CPP部分)、そしてインターフェース(HPP部分)は変更しないでください。レオニダスの引用:「これはカプセル化です!」
クラスの静的メソッドが実際に非メンバー関数を持つ名前空間より優れているのはいつですか?
関数をグループ化してテンプレートにフィードする必要がある場合:
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 !!!
というのも、クラスをテンプレートパラメータにできる場合、名前空間はできません。
#define private public
、ヘッダーに次のコードを追加することです... ^ _ ^ ...
utilities
名前空間で必要なパラメーター(それ以上ではない)を取る関数にテストされるコードを配置することだと思います。このようにして、この関数は単体テストでき、プライベートメンバーへの特別なアクセス権はありません(関数呼び出しでパラメーターとして指定されるため)...
namespace
意志に飛び込んだ場合、彼らはあなたのglobal
にアクセスできません。当然、推測する必要がありますが、コードを意図的に難読化しない限り、変数名はかなり簡単に推測できます。
名前空間に無料の関数を作成することもできます。
BitParser.h内
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
BitParser.cpp内
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
一般に、これはコードを記述するための好ましい方法です。オブジェクトが必要ない場合は、クラスを使用しないでください。
たとえば、C#でできるように、クラスに「静的」キーワードを適用する方法を探している場合
静的クラスはコンパイラーであり、インスタンスのメソッドや変数の記述を阻止します。
インスタンスメソッド/変数を使用せずに通常のクラスを作成する場合も同じです。これはC ++で行うことです。
static
200回書き込んだり、切り取ったり貼り付けたりできないようにコンパイラを手で押さえておくとよいでしょう。
C ++では、(静的クラスではなく)クラスの静的関数を作成します。
class BitParser {
public:
...
static ... getBitAt(...) {
}
};
その後、BitParser :: getBitAt()を使用して、目的の結果であると私が推測するオブジェクトをインスタンス化せずに関数を呼び出すことができるはずです。
次のようなものを書け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 ++では、静的ストレージクラス指定子を使用してクラスメンバーを宣言できます。型宣言でストレージクラス指定子を許可すると、コードがユーザーを混乱させる可能性があります。
と同様にstruct
、class
型宣言でもあります。
同じことは、附属書Aの構文ツリーをたどることによって推定できます。
これはstatic struct
Cでは合法でしたが効果はありませんでした。興味深いのは、Cプログラミングで静的構造体を使用する理由と時期を教えてください。
ここで述べたように、C ++でこれを実現するより良い方法は、名前空間を使用することです。しかし、final
ここでは誰もキーワードを言及していないためstatic class
、C ++ 11以降でのC#の直接の同等物がどのようになるかを投稿します。
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
前に述べたように、C ++で静的クラスを「持つ」ことができます。静的クラスは、インスタンス化されたオブジェクトを持たないクラスです。C ++では、コンストラクタ/デストラクタをプライベートとして宣言することで取得できます。最終結果は同じです。
これは、C ++でC#を使用する方法に似ています。
C#file.csでは、パブリック関数内にプライベート変数を含めることができます。別のファイルにいるときは、次のような関数で名前空間を呼び出すことで使用できます。
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
}
}
OtherFile.h
#include "SharedModule.h"
OtherFile.cpp
//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();
名前空間が「静的クラス」を実現するのにあまり役立たない可能性がある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;
}
};
(多くの)選択肢の1つですが、(名前空間とプライベートコンストラクターを使用して静的動作をエミュレートするのと比較して)最もエレガントな(私の意見では)、C ++で「インスタンス化できないクラス」動作を実現する方法は、private
アクセス修飾子を使用してダミーの純粋仮想関数を宣言します。
class Foo {
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:
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