MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の基礎 - クラスのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の基礎 - クラス
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == <br><br> == staticメンバ == ==== staticメンバ変数 ==== クラスのメンバ変数に<code>static</code>を付加することにより、staticメンバ変数となる。<br> <br> staticメンバ変数は、クラスの定義に記述しただけでは定義したことにならないため、実体となる定義をクラス定義と同じスコープに記述する必要がある。<br> <syntaxhighlight lang="c++"> class CSampleClass { static 型名 メンバ変数名; // 宣言 }; 型名 CSampleClass::メンバ変数名; // 定義 </syntaxhighlight> <br> staticメンバ変数は、オブジェクトを生成せずにプログラムの開始時に既に存在しているため、自動的にゼロで初期化される。<br> ただし、staticメンバ変数の型が、<code>const</code>な整数型、または、<code>const</code>な<code>enum</code>型の場合に限り、宣言と同時に初期化子を与えることができる。<br> <br> <syntaxhighlight lang="c++"> class CSampleClass { private: enum E { e1, e2 }; static const int ci = 100; // OK static const E ce = e1; // OK static const double cf = 1.0; // コンパイルエラー static int i = 100; // コンパイルエラー static E e = e1; // コンパイルエラー }; </syntaxhighlight> <br> コンパイルエラーになるパターンでは、定義時に初期化子を与える必要がある。<br> <syntaxhighlight lang="c++"> class CSampleClass { private: enum E { e1, e2 }; static const int ci = 100; // OK static const E ce = e1; // OK static const double cf; static int i; static E e; }; const double CSampleClass::cf = 1.0; // OK int CSampleClass::i = 100; // OK CSampleClass::E CSampleClass::e = CSampleClass::e1; // OK </syntaxhighlight> <br> 非staticのメンバ変数が、オブジェクト1つごとに別個に存在することに対して、staticメンバ変数は、クラスに対して1つだけ存在する。<br> オブジェクトが複数存在しても、各オブジェクトからただ1つの変数を共有する。<br> <br> <u>このような特徴を持つため、staticメンバ変数は、各オブジェクトが必要とする共通情報を管理することに利用できる。</u><br> <br> 以下の例では、インスタンス化したオブジェクトの総数を管理している。<br> <syntaxhighlight lang="c++"> // CSampleClass.h #ifndef CSAMPLECLASS_H #define CSAMPLECLASS_H class MyClass { public: CSampleClass(); ~CSampleClass(); private: static int msObjectCount; // staticメンバ変数の宣言 }; #endif </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // CSampleClass.cpp #include "CSampleClass.h" // staticメンバ変数の実体 int MyClass::msObjectCount; CSampleClass::CSampleClass() { msObjectCount++; } CSampleClass::~CSampleClass() { msObjectCount--; } </syntaxhighlight> <br> クラスの外部から、staticメンバ変数にアクセスする場合は、<code>クラス名::staticメンバ変数名</code>という形で、スコープ解決演算子を使用して記述する。<br> また、一般的ではないが、非staticなメンバ変数と同様に、<code><オブジェクト名>.<staticメンバ変数名></code>のようなアクセスも可能である。<br> <br> <u>一般的には、staticメンバ変数は非公開である方がよいが、<code>const static</code>を付加している場合は、公開しても問題ない。</u><br> <br> クラスの定義内やメンバ関数の定義内から、自身のクラスのstaticメンバ変数へアクセスする場合は、staticメンバ変数名のみを使用して記述することができる。<br> <br> ==== staticメンバ関数 ==== クラスのメンバ関数にも<code>static</code>指定子を付加することができる。(staticメンバ関数)<br> <syntaxhighlight lang="c++"> class <クラス名> { static <戻り値の型> <メンバ関数名>(<引数>); }; <戻り値の型> <クラス名>::<メンバ関数名>(<引数>) { // ...略 } </syntaxhighlight> <br> staticメンバ関数に<code>const</code>を付加することはできない。<br> また、staticメンバ関数をインライン関数にすることも可能である。<br> <br> staticメンバ関数のオーバーロードも可能であるが、staticメンバ関数と非staticメンバ関数との間において、同じ名前を使用することはできない。<br> <br> staticメンバ変数と同様に、staticメンバ関数もクラスに属するため、staticメンバ関数はオブジェクトを生成せずに呼び出すことができる。<br> <クラス名>::<メンバ関数名>(<引数>) <br> <u>オブジェクト(実体)から呼び出さないため、staticメンバ関数内では、<code>this</code>ポインタを使用することはできない。</u><br> また、一般的ではないが、<code><オブジェクト名>.<staticメンバ関数名>(<引数>)</code>の形で呼び出すことも可能である。<br> <br> 非staticなメンバ関数から、staticメンバ関数を呼び出すことはできるが、<u>staticメンバ関数から、非staticのメンバ変数にアクセスできない。</u><br> <br> <code>public</code>なstaticメンバ関数は、通常の関数と同様に扱うことができるが、<br> クラスに含まれていることにより、スコープを限定できること、staticメンバ変数という専用のデータの置き場が使用できることが特徴である。<br> <br> <syntaxhighlight lang="c++"> #ifndef CSAMPLECLASS_H #define CSAMPLECLASS_H class CSampleClass { public: CSampleClass() { msObjectCount++; } ~CSampleClass() { msObjectCount--; } static int GetObjectCount() { return msObjectCount; } private: static int msObjectCount; // staticメンバ変数の宣言 }; // staticメンバ変数の実体 int CSampleClass::msObjectCount = 0; #endif </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // main.cpp #include <iostream> #include "CSampleClass.h" int main() { std::cout << CSampleClass::GetObjectCount() << std::endl; // msObjectCount : 0 CSampleClass c1; CSampleClass *c2 = new CSampleClass(); std::cout << CSampleClass::GetObjectCount() << std::endl; // msObjectCount : 2 delete c2; std::cout << CSampleClass::GetObjectCount() << std::endl; // msObjectCount : 1 } </syntaxhighlight> <br><br> == staticオブジェクト == staticクラスは、自動的にゼロで初期化された後、staticクラスが宣言された箇所が初めて実行される時にコンストラクタが呼び出される。<br> <br> staticで宣言したクラスの場合、任意の関数が終了してもデストラクタは呼び出されない。<br> staticクラスのデストラクタは、ソフトウェア終了直前に呼び出される。<br> <syntaxhighlight lang="c++"> void func() { static CSampleClass clsSample; } // オブジェクトclsSampleは削除されないため、CSampleClassクラスのデストラクタは呼び出されない </syntaxhighlight> <br><br> == staticクラス == ==== C++ 03以前 ==== 全てのメンバが<code>static</code>メンバであるクラスを、staticクラス(静的クラス)と呼ぶ。<br> <br> staticメンバはオブジェクトを生成せずに使用できるため、staticクラスはインスタンス化の必要性がないことが特徴である。<br> そのため、staticクラスを記述する場合、インスタンス化を禁止するように設計する。<br> <br> C++でインスタンス化を禁止するには、コンストラクタを<code>private</code>にする。<br> <u>なお、コンストラクタが呼び出される可能性は無いため、実装を記述するべきではない。</u><br> <syntaxhighlight lang="c++"> class CSampleClass { private: CSampleClass(); // 唯一のコンストラクタがprivateの場合は、インスタンス化できない }; </syntaxhighlight> <br> <u>問題点として、staticクラスのメンバ関数内において、コンストラクタを使用することである。</u><br> これは、クラス内のメンバへのアクセスとなるため、<code>private</code>であってもアクセス可能となり、コンパイルエラーにならない。<br> <br> これを、コンパイルエラーとする場合、コンストラクタの実装を記述しないことにより、リンクエラーを起こす方法を採ればよい。<br> (コンパイルは通るが、関数の実装が無いというリンクエラーが起きる)<br> <syntaxhighlight lang="c++"> void CSampleClass::func() { CSampleClass *c = new CSampleClass(); } </syntaxhighlight> <br> staticクラスの価値は、任意の機能群を1つのスコープにまとめて記述できることである。<br> 1つのヘッダファイルにstaticクラスの機能群をまとめて、<code><クラス名>::<メンバ></code>のようにスコープを使用してアクセスすることができる。<br> <br> 例えば、ファイルをコピーまたは削除する機能は、それぞれ1つの関数で完結できるため、非staticクラスではメンバ変数を持つ必要はない。<br> 以下の例では、staticクラスを定義して、ファイルをコピーまたは削除する機能を記述している。<br> <syntaxhighlight lang="c++"> class FileSystem { public: static void Copy(const char* src, const char* dest); static void Delete(const char* path); private: FileSystem(); }; </syntaxhighlight> <br> ただし、スコープを限定するという目的の場合、名前空間を使用する方がよい。<br> この場合、コンストラクタを<code>private</code>にする処理も不要である。<br> <syntaxhighlight lang="c++"> namespace FileSystem { void Copy(const char* src, const char* dest); void Delete(const char* path); } FileSystem::Copy("sample.txt", "sample_cp.txt"); FileSystem::Delete("sample.txt"); </syntaxhighlight> <br> ==== C++ 11以降 ==== C++ 11以降では、デフォルトコンストラクタとデストラクタに<code>delete</code>キーワードを指定することにより、実体化を禁止することができる。<br> メンバに<code>delete</code>キーワードを指定する場合は、<code>public</code>に記述することがセオリーである。<br> <br> <code>final</code>は、継承をさせないことを明示的に宣言、または、派生クラスでの仮想関数のオーバーライドをさせないことを明示的に宣言するキーワードである。<br> <syntaxhighlight lang="c++"> // C++ 11以降 class CSampleClass final { public: CSampleClass() = delete; ~CSampleClass() = delete; public: static int Add(int x, int y) { return x + y; } }; </syntaxhighlight> <br> Visual C++では、<code>abstract</code>キーワードが使用できるため、<code>abstract sealed</code>または<code>abstract final</code>を指定することにより、<code>static</code>クラスを記述することができる。<br> ただし、その場合は、他のプラットフォームではそのまま移植できないことに注意が必要となる。<br> <br> また、Visual C++では、コンパイルオプションに<code>/permissive-</code>を付加することにより、独自拡張を無効化することもできる。<br> <br><br> __FORCETOC__ [[カテゴリ:C++]]
C++の基礎 - クラス
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse