シングルトンクラスを実装する場合、通常、構築に関連するいくつかの関数のアクセス許可をプライベートまたは保護(できればプライベート)として設定する必要があります。しかし、大規模なシステムに数十のシングルトンクラスがあり(これは正常であり、シングルトンクラスは実際に最も一般的に使用される外観パターンの設計の1つです)、それぞれをこのように記述するのは面倒なようです。これらの操作で表されるコードを再利用するには、C ++言語継承によって提供される武器を使用できます。
次の基本クラスを設計します。
1 class NonCopyable {
2 public:
3 NonCopyable() = default;
4 NonCopyable(const NonCopyable&) = delete;
5 void operator=(const NonCopyable& c) = delete;
6 };
シングルトンクラスがこのクラスを継承する場合、クライアントはこのシングルトンクラスのインスタンス化されたオブジェクトをコピーまたは割り当てることができないため、メモリ全体にグローバルオブジェクトが1つだけ存在します。ここでのNonCopyableクラスの実装は、boost :: noncopyableを指します。
コンストラクターのアクセス許可の問題を解決した後、別の質問があります。それは、どのようにインスタンス化するかです。シングルトンクラスを実装する古典的な方法は、クラス内のプライベート静的クラスオブジェクトへのポインタを宣言し、getメソッドを使用してこのオブジェクトインスタンスへの参照を返し、この参照を介してクラスの他のメソッドを呼び出すことです。非常に良いですが、シングルトンクラスごとにこれを実装するのはまだ面倒です。現時点では、C ++-templateが提供する別のコード再利用ツールを使用できます。最初に一般的なシングルトンテンプレートクラスを実装し、実装するシングルトンクラスの名前でテンプレートタイプパラメータを渡して、コンパイルフェーズでシングルトンクラスの構築(テンプレートのインスタンス化)を完了します。
一般的なシングルトンテンプレートクラスは、次のように実装されます。
1 template <class T>
2 class Singleton : public NonCopyable {
3 private:
4 static T* inst_;
5
6 public:
7 Singleton() {}
8 virtual ~Singleton() {}
9
10 static T& inst()
11 {
12 if (!inst_) inst_ = new T;
13 return *inst_;
14 }
15
16 static void uninst()
17 {
18 if (!inst_) return;
19 delete inst_;
20 inst_ = nullptr;
21 }
22
23 };
24 //__declspec(selectany)声明使得我们可以在头文件中初始化一个全局变量
25 template <class T> __declspec(selectany) T * Singleton<T>::inst_ = nullptr;
カスタムシングルトンクラスの実装:
1 class singletontest :public Singleton<singletontest>
2 {
3 public:
4 singletontest(){ printf("singletontest constructor function called "); }
5 ~singletontest(){ printf("class test object destroyed "); }
6 //成员方法
7 void print(){
8 printf("singletontest::print function called ");
9 }
10 };
テストコード:
1 singletontest::inst().print(); //line1
2 singletontest a; //line 2 无法阻止默认构造,理想中,单例类只允许出现类似line1的调用
3 printf("singletontest obj a addr is %d\n", &a);
4 a.print();
5 singletontest b;
6 printf("singletontest obj b addr is %d\n", &b);
7 b.print();
8 //a(b); //singletontest继承了noncopyable,继承类初始化时先调用父类的构造函数,由于定义成私有,所以构造失败
9 //a = b; //同上,赋值运算操作符函数同样是私有的
試験結果:
2行目のコードを記述した後、コンパイル中にエラーは報告されません。つまり、オブジェクトはデフォルトの構造を使用して生成されます。この動作を防ぐには、デフォルトのコンストラクターをプライベートとして設定する必要がありますが、inst()メソッドの新しいTは失敗し、ゲインはロスの価値がありません。
コンパイラは、8行目と9行目のテストコードのエラーを識別できます。
コードには3層の継承チェーン(singletontest-> singleton <T>-> Noncopyable)がありますが、クラスで宣言された仮想関数がないため、呼び出しメソッドに回避策がなく、パフォーマンスが低下することはありません。
Singletontest:public sington <singletontest>は、静的多態性を実装するためによく使用されるCRTP(Curiously Recurring Template Pattern)として記述されています。この記事では、あまり紹介しません。
最後に、マルチスレッド環境でのシングルトンクラスの作成について説明する場合、フルスタイルと空腹スタイルの2つの方法がありますが、最新のC ++は静的メンバー変数作成のスレッドの安全性を保証しているため、この方法については説明しません。必要