l VisualC クラス '97.00.00
l.お知らせ 内容 LINK FILE   HTML Win PC Unix MS-DOS C C++ Mfc Java 
目次.C++言語_ 1 クラス 2 派生クラス 5 演算子のオーバーロード クラス(1)
 準備 3 オブジェクト 6 テンプレート 8 etc クラス(2)
 CC++ 4 フレンド・多重継承 7 メモリ確保・例外処理 未使用
 (別ページ)...  変数・ストラクチャの復習  
ストラクチャとクラス (メンバ関数を設ける. クラスにする. ストラクチャとの違い)   デフォルトコンストラクタ   コンストラクタ   関数のオーバーロード   関数のポインタ   デストラクタ   スタティック変数   this ポインタ  

T クラス ストラクチャとクラス
ストラクチャに、そのメンバを処理する専用の関数を付けたものがクラスであると考えることができます。

まず char a と int b をメンバに持つストラクチャを考えてみます。
いずれもビルドして実行してみることができます。
#include <iostream.h> /* ストラクチャ */
struct S        // ストラクチャ S の宣言
{   char a; int b;  // メンバ a b の定義
};
void main()
{ struct S OB;   // オブジェクト OB の宣言
  OB.a='a';        // メンバ a の初期化
  OB.b=123;        // メンバ b の初期化
  cout << OB.a << " " << OB.b << endl;
  char x; cin >> x;
}
VisualC++ では、オブジェクトを宣言するときに struct の記述は省略できます。

メンバ関数を設ける。
メンバの値を表示する部分を関数にして、ストラクチャの中に入れてしまうと次のようになります。
#include <iostream.h>  /* メンバ関数を設ける */
struct S        // ストラクチャ S の宣言
{   char a; int b;  // メンバデータ a b の定義
    void func()     // メンバ関数 func の宣言
    { cout << a << " " << b << endl;}
};

void main()
{ struct S OB;   // オブジェクト OB の宣言
  OB.a='a';        // メンバ a の初期化
  OB.b=123;        // メンバ b の初期化
  OB.func();       // メンバ関数 func の呼び出し
  char x; cin >> x;
}

クラスにする。
普通は上記のようにストラクチャの中にメンバに関数は入れません。
メンバに関数を含む場合は、次のようにクラスとして宣言します。
#include <iostream.h>        /* クラスにする */
class C        // クラス C の宣言
{   public:     // アクセス指定子
    char a; int b;  // メンバデータ a b の定義
    void func()     // メンバ関数 func の宣言
    { cout << a << " " << b << endl;}
};

void main()
{ class C OB;    // オブジェクト OB の宣言
  OB.a='a';        // メンバ a の初期化
  OB.b=123;        // メンバ b の初期化
  OB.func();       // メンバ関数 func の呼び出し
  char x; cin >> x;
}

アクセス指定子 .....ストラクチャとの違い
メンバへのアクセスを許可する範囲を指定します。
アクセス(access : 接近、出入口、発作) :
変数に代入したり関数を呼び出すなど、何かを働きかけること。

public : どこからでもアクセスできます。
private : そのクラスのメンバ関数だけがアクセスできます。
protected : そのクラスのメンバ関数と、派生クラスのメンバ関数だけがアクセスできます。
派生クラス : あるクラスをコピーして作ったクラス。次のページに書かれています。
アクセス指定子を省略すると private になります。

T デフォルトコンストラクタ
ストラクチャやクラスのオブジェクトの宣言は、オブジェクトを構築する(作る)関数を呼び出しているのですが、関数の呼び出し方は普通の関数の場合とは違っています。

このオブジェクトを構築する関数はコンストラクタと呼びます。
自分で作ることもできるので、最初から用意されているオブジエクトを作るだけのコンストラクタはデフォルトコンストラクタと呼んで区別します。

T コンストラクタ (構築子)
クラスでは関数を使ってオブジェクトを構築すると共にデータメンバの値を初期化することができます。
そのための関数はコンストラクタと呼ばれ、他のメンバ関数とは違う点がいくつかあります。

1.コンストラクタの関数名はクラスの名前と同じ名前にします。
2.コンストラクタを呼び出すだけでオブジェクトが構築されます
 定義内容には初期化の方法などだけを書きます。
3.コンストラクタには返り値がありません
4.コンストラクタを呼び出すときは、オブジェクトの宣言と同じ形式で書きます
 他のメンバ関数とは呼び出し方が違います。
5.デフォルトコンストラクタの呼び出しには ( ) を書きません。
C1 OB(3,5); // 引数があるコンストラクタの呼び出し
C1 OB; // デフォルトコンストラクタの呼び出し
 メンバを初期化しないときにはデフォルトコンストラクタを使う必要があります。
6.ひとつでもコンストラクタを宣言すると、最初あらあるデフォルトコンストラクタは消されてしまいます
 デフォルトコンストラクタが必要なときは、あらためて宣言します。


以下はコンストラクタを使った例です。
コンストラクタを呼び出して、オブジェクト OB を作ります。
#include <iostream.h>             /* コンストラクタ */
class C        // クラス C の宣言
{   private:        // アクセス指定子
    char a; int b;  // メンバデータ a b の定義
    public:         // アクセス指定子
    C(char i, int j)    // コンストラクタ C の宣言 
    { a=i; b=j; }
    void func()     // メンバ関数 func の宣言
    { cout << a << " " << b << endl;}
};

void main()
{//C OB; // デフォルトコンストラクタは使用不可 
  C OB('A',123);  // コンストラクタの呼び出し
  OB.func();       // 関数 func の呼び出し
  char x; cin >> x;
}
コンストラクタでオブジェクトを作る(構築する)ことができると共に、引数でメンバデータの値を初期化できるので、データメンバは private(外部からはアクセスできない)にしました。
データメンバに間違った値の代入を防ぐためです。

引数を使わない、オブジェクトを構築するだけのコンストラクタは、デフォルトコンストラクタと呼びます。
自分でコンストラクタを宣言しなかった場合に使用されるコンストラクタには引数がなく、それと同じコンストラクタという意味です。

T 関数のオーバーロード
上の例では、コンストラクタを宣言したために、デフォルトコンストラクタが使用できなくなりました。
ひとつでもコンストラクタを宣言すると、最初からあるデフォルトコンストラクタは消えてしまいます。
デフォルトコンストラクタが必要なときは、あらためて追加します。
VisualC++ では、引数の数 または 型が異なれば同じ名前の関数をいくつでも宣言することができます。

C(char i, int j) { a=i; b=j; } // コンストラクタ 1
C(char i) { a=i; }            // コンストラクタ 2
C(int j) { b=j; }            // コンストラクタ 3
C(){}                       // デフォルトコンストラクタ
デフォルトコンストラクタの呼び出しには ( ) を書きません。
引数の型が区別できない場合
変数と参照 : 呼び出す場合は実引数に変数を与えるので区別できません。
配列名とポインタ : 配列名はポインタなので区別できません。
引数が区別できない場合は、同じ関数名を付けることができません。

T 関数のポインタ
VisualC++ では関数をオーバーロードできます。
関数のポインタを代入するためのポインタ変数は、関数の引数も省略しないで書きます。
void func(int x) { cout << x; }
void (*F) (int);
F=func;
(*F)(7);
// 関数の宣言
// 関数用に、ポインタ変数 F を宣言
// ポインタ変数 F に、関数のポインタを代入
// 関数を、ポインタで呼び出す例
メモ : (引数)の部分を書かないと、変数のポインタと同じ書式です。
 ( int f; → int *F; F=&f; Y=X+*F; ...変数のポインタの例 )


T デストラクタ (消滅子)
関数の中で宣言したオブジェクトは、その関数の動作が終了すると消滅します。
クラスにはオブジェクトが消滅するときに自動的に呼び出されるデストラクタという関数が用意されています。

クラスを宣言すると自動的に作られるデストラクタは何もしない関数です。
デストラクタを自分で作ると、オブジェクトが消滅するときに勝手に呼び出される様子を確かめることができます。
#include <iostream.h>             /* デストラクタ */
class C        // クラス C の宣言
{ public:        // アクセス指定子
  C()    // コンストラクタ C の宣言 
  { cout << "コンストラクタが呼び出されました" << endl; }
  ~C()    // デストラクタ ~C の宣言 
  { cout << "デストラクタが呼び出されました" << endl; }
};
void func() // デストラクタの働きを調べるためにオブジェクトを作る関数
{ C OB; }   // コンストラクタの呼び出し

void main()
{ cout << "関数を呼び出してオブジェクトを作ります。" << endl;
  func();    // 関数の呼び出し
  cout << "関数の呼び出しが終りました。" << endl;
  char x; cin >> x;
}
デストラクタの関数名は、クラス名の前に ~(チルド)を付けたものとします。

デストラクタは勝手に呼び出されるだけなので、引数を使用することはできません。
動的にメモリを確保した場合に、そのメモリを解放するためなどに使われます。

T スタティックデータメンバ
スタティックデータメンバは、グローバル変数をクラス専属のメンバにしたものです。

#include <iostream.h>                  /* static データメンバ */
class C1        // クラス C1 の宣言
{ private: int a;             // 普通のメンバデータの宣言
           static int b; // グローバル変数 x をクラス C1 のメンバとして宣言
  public:  C1(int i, int j) { a=i; b=j; }          // コンストラクタ
           void func() { cout << a << b << endl; } // メンバ関数(表示)
    static void funcS() { cout << b << endl; } // スタティックメンバ関数(表示)
};
int C1:: b;     // クラス C1 用のグローバル変数 b を宣言
// クラスのメンバにするグローバル変数は、{クラス}の後に書きます。

void main()
{ C1 OB(5,7);  // クラス C1 のオブジェクト OB を宣言/初期化
  OB.func();   // メンバ関数の呼び出し。(表示)
  C1::funcS();   // スタティックメンバ関数の呼び出し。
  int q; cin >> q;
}
スタティックデータメンバだけを扱うメンバ関数は、 スタティックメンバ関数として宣言します。

T this ポインタ
クラスを宣言すると、this というポインタ変数が勝手にデータメンバに加わります。
オブジェクトを構築すると、this にはオブジェクトのポインタが代入されます。
this ポインタは、後記の「演算子のオーバーロード」などで使用されます。
メモ : オブジェクトはクラスという設計図を元に作られた実際のプログラムの部分です。
同じクラスのオブジェクトが複数構築された場合は、オブジェクト毎に this ポインタがあります。

this ポインタの宣言はソースファイルには書かれませんが、次のように使用できます。
#include <iostream.h> /* this ポインタ */
class C1        // クラス C1 の宣言
{ private: int a;
//         C1 *this; ← 書かれてないが this ポインタが宣言されている
  public:
   C1(int i) { a=i; }                  // コンストラクタ
   void func1() { cout << this->a << endl; } // 表示用のメンバ関数
   // this->a は、この例では OB.a と同じ意味を持ちます。
   // 単に a と書いてもよいのですが、this ポインタの使用例として使っています
};
class C2        // クラス C2 の宣言
{ public:
  void func2()
  { C1 OB(5);        // クラス C1 のオブジェクトを宣言 
    OB.func1();      // クラス C1 のメンバ関数を呼び出し
  }
};
void main()
{ C2 OB2;      // クラス C2 のオブジェクトを宣言
  OB2.func2(); // クラス C2 のメンバ関数を呼び出し
  cout << "文字を入力して下さい"; char x; cin >> x;
}

this ポインタとメンバ関数
オブジェクトを宣言すると、設計図(クラス)を元にして、具体的な内容が作られます。
複数のオブジェクトを宣言すると、クラスのメンバはオブジェクトの数だけ作られます。

ところで、メンバデータにはオブジェクト毎に別々な値を代入しますが、メンバ関数は全て同じです。
同じ物を複数作るのはメモリをムダに使うことになりますから、実際には、同じクラスのメンバ関数は一組だけ作られます。

一組のメンバ関数を、それぞれのオブジェクトのメンバとして働かせるために this ポインタが利用されます。
メンバ関数が他のメンバを処理するとき、オブジェクトが指定されていない場合には、自動的に this ポインタを使うようになっています。

this ポインタは、オブジェクトを宣言するとコンストラクタによって作られます。
メンバ関数は、呼び出し時に指定されたオブジェクトの this ポインタを使うようになっているので、メンバ関数の 定義 にはオブジェクトの記述を省略できるわけです。
#include <iostream.h>     /* this ポインタとメンバ関数 */
class C1           // クラス C1 の宣言
{   public:
    int a;          // メンバデータ a
//  const C1 *this; // ポインタ変数 this (代入禁止)
//  this は勝手に宣言されます。プログラマが宣言することはできません。
    C1() { }        // コンストラクタ
//  { this=&OB; }   // this をオブジェクトのポインタで初期化
//  this は勝手に初期化されます。プログラマが代入することはできません。
    void func(int x)// メンバ関数 func
    { this->a=x; }  // OB.a に x を代入
//  func()は、オブジェクト OB の this ポインタを使うように呼び出されます。
};
void main()
{ C1 OB;            // オブジェクト OB の宣言
  // OB のメンバデータ this は、OB のポインタで初期化されます。
  OB.func(5);       // メンバ a に 5 を代入
  // func()は、オブジェクト OB の this ポインタを使います。
  cout << OB.a << endl;
  char q; cin >> q;
}

T

C++言語 1 クラス 2 派生クラス
 
  mtoga@sannet.ne.jp   登録日 '96. 6.15
URL : http://www.page.sannet.ne.jp/mtoga/index.html