クラスの基礎
シンプルなクラス
まずはごく簡単なクラスのサンプルコードを示します。
#include <iostream>
#include <string>
//クラス「SimpleClass」を定義
class SimpleClass
{
public:
int number;
std::string name;
};
int main()
{
//定義したクラスの変数(インスタンス)を宣言
SimpleClass sc;
sc.number = 0;
sc.name = "〇山×夫";
std::cout << "number: " << sc.number;
std::cout << "\nname: " << sc.name << std::endl;
std::cin.get();
}
5~10行目がクラスの定義です。
クラスはclassというキーワードで定義します。
クラスの最後は「;」(セミコロン)で終了します。
クラスというのは構造体によく似ています。
実際にmain関数内の処理だけを見ると、まるで構造体を使用しているように見えます。
(C++においては、クラスと構造体に違いはほとんどありません)
アクセス修飾子
8行目にpublic:というキーワードがあります。
これはアクセス修飾子といいます。
(最後の「:」を忘れないように)
アクセス修飾子はクラスのカプセル化のために必要な機能です。
「public:」を付けて宣言されたメンバ変数は、外部から自由にアクセスが可能、という意味になります。
アクセス修飾子には以下があります。
- private
-
そのクラス内からのみアクセスが可能。
何も指定しない場合はprivateになる。
(デフォルト) - public
- どこからでもアクセスが可能。
- protected
- そのクラスと、そのクラスを継承したクラスからのみアクセスが可能。
protectedは継承という機能に関係するアクセス修飾子です。
これはまた後に説明します。
アクセス修飾子は以下のように記述します。
class SimpleClass
{
private: //ここからprivate
int a;
int b;
public: //ここからpublic
int c;
int d;
protected: //ここからprotected
int e;
int f;
private: //ここからprivate
int g;
int h;
};
クラス内にアクセス修飾子を書くと、そこから先のメンバ変数はそのアクセス制限の変数となります。
新たなアクセス修飾子を書くと、そこからはまた別のアクセス制限の変数となります。
アクセス修飾子は何度でも書けますが、同じアクセス制限の変数はまとめてしまった方が見やすいでしょう。
アクセス修飾子を付けない場合、自動的にprivateが指定されたものとみなされます。
そのため、明示的にpublicを指定しないと外部からクラスのメンバ変数にアクセスが出来なくなります。
#include <iostream>
#include <string>
//クラス「SimpleClass」を定義
class SimpleClass
{
//privateとみなされる
int number;
public: //ここからpublic
std::string name;
};
int main()
{
//定義したクラス型変数(インスタンス)を宣言
SimpleClass sc;
//アクセスできない
sc.number = 0;
//アクセスできる
sc.name = "〇山×夫";
}
インスタンス
main関数内では定義したクラス型の変数を宣言し、使用しています。
クラス型の変数は、変数よりもインスタンスという呼び方をされます。
クラスというのは物の設計図のようなものです。
設計図を書いても、実際に製品を作らなければ使うことはできません。
クラス定義を元に「実体」を作ることをインスタンス化するといいます。
インスタンスは必要なだけいくつでも作ることができます。
クラスをデータ型とみなし、その型の変数を作ることで自動的にインスタンスが生成されます。
何か特別な名前がついていますが、難しく考える必要はありません。
構造体を使用するために構造体変数を宣言するのと同じようなもの、と考えると良いです。
基本的に「クラス型変数=クラスのインスタンス」と考えて差し支えありませんが、クラスをポインタで扱う場合は必ずしも正しくないので注意してください。
クラスをポインタで扱う方法は後述します。
メンバ関数
クラスは内部に変数を持つことができますが、関数を持つこともできます。
これをメンバ関数と言います。
(クラス内変数をメンバ変数と呼ぶのと同じです)
#include <iostream>
#include <string>
class SimpleClass
{
private:
int number;
std::string name;
public:
int GetNumber()
{
return number;
}
void SetNumber(int n)
{
number = n;
}
std::string GetName()
{
return name;
}
void SetName(char* s)
{
name = s;
}
};
int main()
{
SimpleClass sc;
sc.SetNumber(0);
sc.SetName("〇山×夫");
//privateメンバなので
//こういう方法ではアクセスできなくなっている
//sc.number = 0;
std::cout << "number: " << sc.GetNumber();
std::cout << "\nname: " << sc.GetName() << std::endl;
std::cin.get();
}
先ほどのサンプルコードのクラスのメンバ変数をすべてprivateに変更しています。
アクセッサ
メンバ変数がprivateになったので、「sc.number」といった方法では外部からアクセスできなくなりました。
その代わりとして、メンバ関数をpublicで定義して、そこからメンバ変数にアクセスできるようにしています。
(メンバ関数内からはメンバ変数にアクセスできます)
このようなメンバ変数を読み書きするためのメンバ関数をアクセッサ(アクセサ)と言います。
特に、値を取得するためのアクセッサをgetter(ゲッター)、値を設定するためのアクセッサをsetter(セッター)と言います。
メンバ変数をprivateにすることで、外部からアクセスできなくなり情報の隠蔽ができたように見えます。
しかしこのコードは、隠蔽方法としては全く無意味です。
なぜならば、直接メンバ変数にアクセスできなくともアクセッサを通して値の読み書きが自由に行えるので、隠蔽したことにならないからです。
つまりメンバ変数をpublicで定義するのと何ら変わりません。
必要のない操作まで許可しないのが基本的な考え方です。
今回のようなサンプル程度では隠蔽化しようがないので、この辺のことはおいおい説明していきます。
クラステンプレート
関数テンプレートでは、関数内で使用するデータ型を、関数呼び出し時に決定することができました。
(C++の関数参照)
これと同じことがクラスでも可能です。
#include <iostream>
#include <string>
template<typename T>
class TestClass
{
T value;
public:
void Set(T val)
{
value = val;
}
T Get()
{
return value;
}
void Print()
{
std::cout << value << std::endl;
}
};
int main()
{
TestClass<int> tc1;
tc1.Set(10);
tc1.Print();
TestClass<std::string> tc2;
tc2.Set("ABC");
tc2.Print();
std::cin.get();
}
10 ABC
使い方はほとんど関数テンプレートと同じです。