「C++の基礎 - クラス」の版間の差分
(→概要) |
|||
57行目: | 57行目: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br> | <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> | <br><br> | ||
2022年12月3日 (土) 16:44時点における版
概要
staticメンバ
staticメンバ変数
クラスのメンバ変数にstatic
を付加することにより、staticメンバ変数となる。
staticメンバ変数は、クラスの定義に記述しただけでは定義したことにならないため、実体となる定義をクラス定義と同じスコープに記述する必要がある。
class CSampleClass
{
static 型名 メンバ変数名; // 宣言
};
型名 CSampleClass::メンバ変数名; // 定義
staticメンバ変数は、オブジェクトを生成せずにプログラムの開始時に既に存在しているため、自動的にゼロで初期化される。
ただし、staticメンバ変数の型が、const
な整数型、または、const
なenum
型の場合に限り、宣言と同時に初期化子を与えることができる。
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; // コンパイルエラー
};
コンパイルエラーになるパターンでは、定義時に初期化子を与える必要がある。
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
非staticのメンバ変数が、オブジェクト1つごとに別個に存在することに対して、staticメンバ変数は、クラスに対して1つだけ存在する。
オブジェクトが複数存在しても、各オブジェクトからただ1つの変数を共有する。
このような特徴を持つため、staticメンバ変数は、各オブジェクトが必要とする共通情報を管理することに利用できる。
以下の例では、インスタンス化したオブジェクトの総数を管理している。
// CSampleClass.h
#ifndef CSAMPLECLASS_H
#define CSAMPLECLASS_H
class MyClass
{
public:
CSampleClass();
~CSampleClass();
private:
static int msObjectCount; // staticメンバ変数の宣言
};
#endif
// CSampleClass.cpp
#include "CSampleClass.h"
// staticメンバ変数の実体
int MyClass::msObjectCount;
CSampleClass::CSampleClass()
{
msObjectCount++;
}
CSampleClass::~CSampleClass()
{
msObjectCount--;
}
クラスの外部から、staticメンバ変数にアクセスする場合は、クラス名::staticメンバ変数名
という形で、スコープ解決演算子を使用して記述する。
また、一般的ではないが、非staticなメンバ変数と同様に、<オブジェクト名>.<staticメンバ変数名>
のようなアクセスも可能である。
一般的には、staticメンバ変数は非公開である方がよいが、const static
を付加している場合は、公開しても問題ない。
クラスの定義内やメンバ関数の定義内から、自身のクラスのstaticメンバ変数へアクセスする場合は、staticメンバ変数名のみを使用して記述することができる。
staticメンバ関数
クラスのメンバ関数にもstatic
指定子を付加することができる。(staticメンバ関数)
class <クラス名>
{
static <戻り値の型> <メンバ関数名>(<引数>);
};
<戻り値の型> <クラス名>::<メンバ関数名>(<引数>)
{
// ...略
}
staticメンバ関数にconst
を付加することはできない。
また、staticメンバ関数をインライン関数にすることも可能である。
staticメンバ関数のオーバーロードも可能であるが、staticメンバ関数と非staticメンバ関数との間において、同じ名前を使用することはできない。
staticメンバ変数と同様に、staticメンバ関数もクラスに属するため、staticメンバ関数はオブジェクトを生成せずに呼び出すことができる。
<クラス名>::<メンバ関数名>(<引数>)
オブジェクト(実体)から呼び出さないため、staticメンバ関数内では、this
ポインタを使用することはできない。
また、一般的ではないが、<オブジェクト名>.<staticメンバ関数名>(<引数>)
の形で呼び出すことも可能である。
非staticなメンバ関数から、staticメンバ関数を呼び出すことはできるが、staticメンバ関数から、非staticのメンバ変数にアクセスできない。
public
なstaticメンバ関数は、通常の関数と同様に扱うことができるが、
クラスに含まれていることにより、スコープを限定できること、staticメンバ変数という専用のデータの置き場が使用できることが特徴である。
#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
// 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
}
staticオブジェクト
staticクラスは、自動的にゼロで初期化された後、staticクラスが宣言された箇所が初めて実行される時にコンストラクタが呼び出される。
staticで宣言したクラスの場合、任意の関数が終了してもデストラクタは呼び出されない。
staticクラスのデストラクタは、ソフトウェア終了直前に呼び出される。
void func()
{
static CSampleClass clsSample;
}
// オブジェクトclsSampleは削除されないため、CSampleClassクラスのデストラクタは呼び出されない
実体化の禁止
C++11以降では、デフォルトコンストラクタとデストラクタにdelete
キーワードを指定することにより、実体化を禁止することができる。
メンバにdelete
キーワードを指定する場合は、public
に記述することがセオリーである。
// C++11以降
class CSampleClass final
{
public:
CSampleClass() = delete;
~CSampleClass() = delete;
public:
static int Add(int x, int y)
{
return x + y;
}
};
Visual C++では、abstract
キーワードが使用できるため、abstract sealed
またはabstract final
を指定することにより、static
クラスを記述することができる。
ただし、その場合は、他のプラットフォームではそのまま移植できないことに注意が必要となる。
また、Visual C++では、コンパイルオプションに/permissive-
を付加することにより、独自拡張を無効化することもできる。