構造体とクラス構造

構造体とクラス構造

クラス(class)とは構造体の機能を強化したものです。
以前に説明した構造体を思い出して下さい。
以下のような物でした。
説明が煩雑になるので要素の数は減らしてあります。

構造体の例 ----------------
 

 struct partychara{
 char *name; // 個人名(ポインタ)
 int trib; // 種族 0-12 まである
 int age; // 年齢
 };
 

使うときには

partychara[5];

partychara[5].name = "金太郎";

の様に使いました。
これをクラスで表現すると

クラスの例 ------------------
 

 class partychara{
 private
 int kaisu;
 
 protected
 char *name;
 int trib;
 int age;
 
 public
 void setname(char *nameis);
 char *getname();
 void settrib(int tr);
 int gettrib();
 void setage(int ageis);
 int getage();
 }
 
 void partychara::setname(char *nameis)  { name = nameis; }
 
 char* partychara::getname() { return name; }
 
 void partychara::settrib(int tribis) { trib = tribis; }
 
 int partychara::gettrib() { return trib; }
 
 void partychara::setage(int ageis) { age = ageis; }
 
 int partychara::getage() { return age; }
 

おおっと、5行で済んだ構造体をクラスとして定義すると
30行以上になっています。
何をやっているかわからん、という感想はさておきコードが6倍にもなってしまうクラスにすることでなにか良いことがあるのでしょうか。

いままでの構造体の代わりにクラスを使う、というのではほとんどメリットがありません。
無いこともないのですが、むしろクラスにしたことで新しいメリットが生まれプログラム設計の考え方が変わってしまう、という意味のほうがずっと大きいのです。

まず構造体からクラスに置き換えただけのメリットとしてはデバッグのしやすさがあげられます。
あるバグがあるとします。
このバグは、上の例の構造体の trib に変な値がはいってしまうもととしましょう。
構造体の場合では、

partychara.trib = 0

とやればどこからでもtrib の内容を変更できます。
どこかのバグがここを書き換えていたとするとその個所を特定するのは非常に困難です。
ましてやポインタのバグだったりするとえらく時間がかかります。

クラスの場合は trib にアクセスするためには settrib gettrib という関数を使わないと不可能になっています。
trib に変な値が入る、というようなバグは、クラスに書き換えたとたんになくなると言ってよいしょう。
あったとしても gettrib settrib にブレークポイントをかけて実行すると
tribを書き換えているバグの場所を特定するのは簡単です。

また、良くあるバグの一つに変数の中に -5464938 などという数が入る、という現象があります。
年齢を際限なく引いていったりするとなりますね。
この場合も
 

 partychara.setage(int ageis) // 年齢をセットするメンバ関数
 {
 if (ageis > 0) // 年齢が0歳以上で
  if (ageis < 300) // 300歳以下なら
   age = ageis; // 年齢セット
 }
 

といったふうに書くとセットする年齢に制限を加えることができます。
構造体を使うと年齢をセットするたびに同じチェックを何回もしなければなりません。
以上が単にクラスに置き換えた場合の一番のメリットと言えます。

では、クラスを使うおかげで得られる新しいメリットとはどんなものでしょうか。
それは、VC++におけるクラスの働きを理解したあとで説明しましょう。

さてクラスですが、一行づつ行きましょう。

まず、クラスの宣言です。
クラスの中に宣言されている変数や関数は、メンバーと呼ばれます。
変数の場合はメンバ変数、関数の場合はメンバ関数です。

 

class partychara{ // クラスの宣言
 
private(プライベート)変数、あるいは関数は外部からアクセスできない部分です。
たとえば
 
partychara p1;
p1.kaisu = 0;
 
という事はできません。
この例では外部から使える
setkaisu()、 getkaisu()といった関数が定義されていないので
外部からアクセスできない変数ということになります。
なにか意味があるのでしょうか。
ここではkaisu とはこのクラスにアクセスした回数を保持していると仮定しましょう。
すると、dispkaisu() という関数を定義すると外部から参照できることになります。
おまけにこの変数は外部から書き換えることは不可能なので信頼性が高まるというわけです。
 
private // private メンバーの宣言
int kaisu;
 
protected(プロテクテド) は機能としてはprivate と同じです。
これはクラスを導入するときに新設されたキーワードです。
クラスを継承するときに必要なので継承の説明の時に一緒に説明します。
private と同じく外部からはアクセスできない、と覚えて下さい。
 
protected // protected メンバーの宣言
char *name;
int trib;
int age;
 
public(パブリック)は公共のというわけで外部から自由にアクセスできるメンバーです。
 
partychara p1;
 
p1->settib(15);
 
などと使います。
 
public // public メンバーの宣言
void setname(char *nameis);
char *getname();
void settrib(int tr);
int gettrib();
void setage(int ageis);
int getage();
}
 

以上がクラス宣言の内訳です。