クラス
クラス
クラス (class) は,メンバ変数,メンバ関数などをメンバに持つデータ型で,次のように定義します。
最後にセミコロンが必要なのは,C の構造体と同様,クラスの定義と同時にオブジェクトの定義も可能なためです。
class クラス名
{
メンバの宣言
};
次のプログラムは,時計を表す Clock クラスを定義したものです。
#include <cstdio>
// Clock クラスの定義
class Clock
{
public:
int hour;
int minute;
void set(int hour, int minute);
void print();
};
void Clock::set(int hour, int minute)
{
this->hour = hour % 24;
this->minute = minute % 60;
}
void Clock::print()
{
printf("%02d:%02d\n", hour, minute);
fflush(stdout);
}
int main()
{
Clock c; // インスタンス化
c.set(6, 30);
c.print(); // 出力: 06:30
}
時計を表すクラス Clock の具現化である c は,Clock クラスのインスタンス (instance) またはオブジェクト (object) と呼ばれます。
## メンバ変数の初期化
クラス定義内で,static const でないメンバ変数を int hour = 0; のように初期化することは禁止されています。
メンバ変数を初期化する方法については,コンストラクタの説明と共に説明します。
メンバ関数の定義
今回の Clock クラスでは,クラス定義の中にはメンバ関数の宣言のみを書き,関数の定義はクラス定義の外に記述しました。
関数定義 void Clock::set(...) { ... } における記号 :: は,スコープ解決演算子です。
関数定義が短い場合,関数定義をクラス定義の中に直接記述することもあります。
この方法で書かれた関数はインライン関数と呼ばれ,コンパイル時にインライン展開されます。
class Clock
{
public:
int hour;
int minute;
void set(int hour, int minute) { /* ... */ }
void print() { /* ... */ }
};
this ポインタ
クラス内部では,自身のオブジェクトへのポインタである this ポインタが利用できます。
今回の set 関数のように,メンバ hour と仮引数 hour の名前が重複した場合,前者を this->hour,後者を hour と書き分けて区別することができます。
アクセス指定子
Clock クラスのメンバ変数 hour, minute をクラスの外部からアクセス不能にするには,次のようにアクセス指定子 private を指定します。
このようにすれば,c.hour = -64 などと不正な値が設定されるのを防ぐことができます。
class Clock
{
private:
int hour; // 非公開
int minute; // 非公開
public:
void set(int, int); // 公開
void print(); // 公開
};
アクセス指定子には,public, private, protected の 3 つがあります。
アクセス指定子 | 説明 |
---|---|
public | クラスの内部および外部からアクセス可能 |
private | クラスの内部からのみアクセス可能 |
protected | 派生クラスを含むクラスの内部からのみアクセス可能 |
クラスにおいてアクセス指定子を省略した場合は,private アクセスレベルが適用されます。
class Clock
{
int hour; // 非公開
int minute; // 非公開
public:
void set(int, int); // 公開
void print(); // 公開
};
フレンド
フレンド (friend) とは,特定の関数やクラスに対して,あるクラスの非公開メンバへのアクセス権を与える機能です。
次のプログラムは,クラス Class1 について func1() をフレンド関数に,ClassFriend をフレンドクラスに指定したものです。
class Class1
{
private:
friend void func1(Class1&); // フレンド関数
friend class ClassFriend; // フレンドクラス
int num;
};
void func1(Class1& c)
{
c.num = 123;
}
class ClassFriend
{
public:
static void func2(Class1& c) { c.num = 456; }
};
int main()
{
Class1 c;
func1(c);
ClassFriend::func2(c);
}
静的メンバ
宣言に static を付けたメンバは静的メンバと呼ばれ,クラスをインスタンス化せずに利用できます。
次のプログラムは,静的メンバ n, func1 を持つクラスを定義したものです。
class Class1
{
public:
static int n; // 静的メンバ変数の宣言
static void func1() { }
};
// 静的メンバ変数の定義
int Class1::n = 1;
int main()
{
Class1::n;
Class1::func1();
}
静的メンバにアクセスするには,Class1::n のように,クラス名::メンバ名 と書きます。
ただし,c が Class1 クラスのインスタンスであるとき,c.n のように呼び出してもいいです。
const でない静的メンバ変数は,クラス定義内に書く宣言とは別に,クラス定義の外側に定義を書かなければなりません。
定義において初期化子を省略した場合,大域変数と同様 0 に初期化されます。
構造体とクラスの違い
C++ では,構造体とクラスとの間に本質的な違いはありません。
構造体は,クラスと同様にメンバ関数を持つことができ,クラスと同様に継承が可能です。
構造体とクラスの唯一の違いは,構造体のデフォルトアクセスレベルが public なのに対し,クラスのデフォルトアクセスレベルが private であることです。
class Class1
{
void f(); // 非公開
public:
void g(); // 公開
};
class Struct1
{
void f(); // 公開
private:
void g(); // 非公開
};