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 メモリ確保・例外処理 未使用
関数の中に構築   メンバオブジェクト(メンバイニシャライザなし)   メンバイニシャライザ 基本イニシャライザ   メンバオブジェクト(メンバイニシャライザあり)   グローバルオブジェクト   スタティックオブジェクト   オブジェクトの配列   const オブジェクト   コピーコンストラクタ  

オブジェクトの構築
ソースファイルを短くするために、一般的ではありませんが、メンバ関数を全てインライン関数にして書いています。

T 関数の中に構築する
#include <iostream.h>                /* 関数の中にオブジェクトを構築 */
class C1        // クラス C1 の宣言
{ private: int a;
  public: C1(int i) { a=i; }                  // コンストラクタ
          void func1() { cout << a << endl; } // 表示用のメンバ関数
};
class C2   // クラス C2 の宣言
{ public:
  void func2()
  { C1 OB(5);   // クラス C1 のオブジェクトを宣言 
    OB.func1(); // クラス C1 のメンバ関数を呼び出し
  }
};
// クラス C1 を、C2 のメンバとしてではなく、そのまま使っています。
// オブジェクト OB は、関数 func1 の動作が終了すると消去されます。
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }


T メンバオブジェクトを構築する (メンバイニシャライザなし)
クラスのメンバとして他のクラスのオブジェクトを宣言すると、そのクラスのオブジェクトの中にオブジエクトが作られます。
#include <iostream.h>          /* メンバオブジェクト(メンバイニシャライザなし) */
class C1  // クラス C1 の宣言
{ private: int a;
  public: void set(int i) { a=i; }            // 代入用のメンバ関数
          void func1() { cout << a << endl; } // 表示用のメンバ関数
};
class C2  // クラス C2 の宣言
{ public:
  C1 OB;  // メンバオブジェクトを宣言(クラス C1 のオブジェクト)
   // クラス C1 のデフォルトコンストラクタが呼び出されます。
   // メンバの宣言なので引数付のコンストラクタは使用できません。
  void func2()
  { OB.C1::set(5);  // クラス C1 のメンバ関数を呼び出します。
    OB.C1::func1(); //   〃
  }
};
// オブジェクト OB は、クラス C2 のオブジェクト(OB2)が構築されるときに作られ、
// クラス C2 のオブジェクト(OB2)が消滅するときに消去されます。
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }


T メンバイニシャライザ
コンストラクタには、メンバデータの値を初期化するための特別な書式があります。
コンストラクタには、メンバイニシャライザを付けることができます。

まず、普通のコンストラクタの例を示します。
class C1
{ private :
int a; int b; // メンバデータ
C1(int i, int j)
{ a=i; b=j; }
// コンストラクタ
// (定義内容)
};
// コンストラクタは引数 i, j の値をメンバデータ a, b に代入します。

メンバイニシャライザは、初期化したいメンバデータの後に()を付け、その中に初期化したい値を書いたものです。
上の例をメンバイニシャライザを使って書くと、次のようになります。
class C1
{ private : int a; int b; // メンバデータ
C1(int i, int j)
: a(i), b(j)
{ /**/ }
// コンストラクタ
// メンバイニシャライザ
// (その他の定義内容)
};
// メンバイニシャライザは C1 の引数 i, j の値を、メンバデータ a, b に代入します。
// C1 の引数を使わずに、直接値を与えてもかまいません。
const メンバを初期化する場合は、メンバイニシャライザを使う必要があります。

基本イニシャライザ
メンバオブジェクトを初期化するためのメンバイニシャライザは、基本イニシャライザと呼びます。
基本イニシャライザは、メンバオブジェクトのクラスのコンストラクタを呼び出して、自分が受け取った引数を呼び出したコンストラクタに与えます。
次の例は、基本イニシャライザを使ってメンバオブジェクトを構築する例です。

T メンバオブジェクトを構築する (メンバイニシャライザあり)
基本イニシャライザを使うと、メンバオブジェクトのクラスの、引数付のコンストラクタを呼び出すことができます。
#include <iostream.h>           /* メンバオブジェクト(メンバイニシャライザあり) */
class C1  // クラス C1 の宣言
{ private: int a;
  public: C1(int i) { a=i; }                  // コンストラクタ
          void func1() { cout << a << endl; } // 表示用のメンバ関数
};
class C2  // クラス C2 の宣言
{ public:
  int b;    // メンバデータ
  C1 OB;    // メンバオブジェクトを宣言(クラス C1 のオブジェクト)
  C2()      // コンストラクタ(デフォルトコンストラクタ)
  : OB(5),b(7) // メンバイニシャライザ
  { cout << "コンストラクタ C2 が呼び出されました" << endl; }
   // OB(5)の基本イニシャライザは、C1 のコンストラクタを呼び出します。
   // b(7)のイニシャライザは、メンバ b を 7 で初期化します。
   // コンストラクタ C2 は、クラス C2 のオブジェクトを作る他に、以上の動作をします。
  void func2()
  { OB.C1::func1();    // クラス C1 のメンバ関数を呼び出します。(表示)
    cout << b << endl; // メンバ b の値を表示します。
  }
};
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }


T 参考 グローバルオブジェクトを構築する
{関数}や{クラス}の外側で宣言したオブジェクトは、グローバルオブジェクトになります。
#include <iostream.h>           /* グローバルオブジェクト */
class C1  // クラス C1 の宣言
{ private: int a;
  public: C1(int i) { a=i; }                  // コンストラクタ
          void func1() { cout << a << endl; } // 表示用のメンバ関数 
} OB(5);   // グローバルオブジェクト OB を宣言
C1 OB3(2); //  〃   OB3
// オブジェクト OBOB3 は、プログラムが終了するまで消去されません。
class C2  // クラス C2 の宣言
{ public:
  void func2()
  { OB.C1::func1(); } // クラス C1 のメンバ関数を呼び出します。
};
void main( ) { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し char q; cin >> q; }


T スタティックオブジェクトを構築する
static を付けて書けば、クラスの中でも消滅しないオブジェクトを宣言できます。
スタティック(static : 静的な) : 変化、消滅しないでそのまま残っていること。

スタティックオブジェクトは原則として、宣言したクラスに所属します。
しかし次の例は、オブジェクトのポインタをグローバル変数に代入しているので、結果的にグローバルオブジェクトになっています。
ポインタ変数をデータメンバにしてしまえばよいのですが、それは後記の「スタティックデータメンバ」で述べます。
#include <iostream.h>               /* スタティックオブジェクト */
class C1        // クラス C1 の宣言
{ private: int a;
  public: C1(int i) { a=i; }                  // コンストラクタ
          void func1() { cout << a << endl; } // 表示用のメンバ関数
          void funcA() { a=a+1; }             // a を +1 するメンバ関数
};
C1 *p;     // ポインタ変数 p を宣言(グローバル変数)
// この p にスタティックオブジェクトのポインタを格納します。
 
class C2   // クラス C2 の宣言
{ public:
  void func_S()
  { static C1 OB(5); // スタティックオブジェクトを宣言( C1 のオブジェクト)
  // スタティックオブジェクトは、プログラムが終了するまで消去されません。
    p=&OB;           // スタティックオブジェクトのポインタを p に格納 
  }
  void func2()
  { p->func1(); // クラス C1 のメンバ関数を呼び出し(表示)
    p->funcA(); //  〃      (a を +1 する。)
  }
};
void main() { C2 func_S(); // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し // オブジェクト OB は、関数 func2 の動作が終了してもそのまま残っています。 OB2.func2(); // クラス C2 のメンバ関数を再び呼び出し // func2() を呼び出すたびに a の値が +1 されていて、 // オブジェクトがそのまま残っていることがわかります。 cout << "文字を入力して下さい"; char x; cin >> x; }
スタティックオブジェクト OB は、関数 func_S() で宣言しました。
関数 func_S() の動作が終了した後でもオブジェクト OB にアクセスできるように、オブジェクトのポインタをグローバル変数 p に保存しています。

T オブジェクトの配列を構築する
#include <iostream.h>               /* オブジェクトの配列 */
class C1        // クラス C1 の宣言
{ private: int a; int b;
  public: C1(int i,int j) { a=i; b=j; }            // コンストラクタ
          void func1() { cout<<a<<" "<< b<<endl; } // 表示用のメンバ関数
};
class C2   // クラス C2 の宣言
{ public:
  void func2()
  { C1 OBa(2,5);              // クラス C1 のオブジェクトを宣言 
    C1 OBb[3]={C1(1,2),C1(3,4),C1(5,6)}; // オブジェクトの配列を宣言 
    // この場合はプライベートデータメンバなので、配列全体を初期化します。
    // パブリックデータメンバなら、最初の一部だけの初期化が可能です。
    OBb[0].func1(); // クラス C1 のメンバ関数を呼び出し
  }
};
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }


T const オブジェクト(代入禁止オブジェクト)を構築する
コンスト(const=constant:定数、定量、不変の) : ここでは別な値を代入できない意味。
#include <iostream.h>               /* 代入禁止オブジェクト */
class C1        // クラス C1 の宣言
{ public: int a;
          C1(int i){ a=i; }                      // コンストラクタ
          void func()const{ cout << a << endl; } // 表示用のメンバ関数 
          // const オブジェクトで使う関数はあらかじめ const を書いておきます。
};
class C2   // クラス C2 の宣言
{ public:
  void funcA()
  { C1 OBa(5);       // クラス C1 のオブジェクトを宣言 
    OBa.a=3;         // パブリックメンバには別な値を代入できます。
    OBa.func();      // クラス C1 のメンバ関数を呼び出し(表示)
    // const メンバ関数は、代入可能オブジェクトにもそのまま使用できます。
  }
  void funcB()
  { const C1 OBb(7); // const オブジェクトを宣言 
    // パブリックメンバでも const と宣言したオブジェクトのメンバには
    // 別な値を代入することはできません。
    OBb.func();      // クラス C1 のメンバ関数を呼び出し(表示)
  }
};
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.funcA(); // クラス C2 のメンバ関数を呼び出し OB2.funcB(); //  〃 cout << "文字を入力して下さい"; char x; cin >> x; }


T コピーコンストラクタでコピーを作る
コンストラクタを呼び出すとオブジェクトが構築されます。
そのときコンストラクタを、既存のオブジェクトのメンバの値をコピーするように定義しておけば、既存オブジェクトのコピーが作られることになります。
オブジェクトのコピーを作るためのコンストラクタは、コピーコンストラクタと呼ばれます。

次の例は、仮引数に既存オブジェクトを受け取って、新しく構築するオブジェクトにメンバの値をコピーする例です。
#include <iostream.h>          /* コピーコンストラクタ */
class C1        // クラス C1 の宣言
{ private: int a;
  public: C1(int i) { a=i; }                  // コンストラクタ
  public: C1(C1 ob) { a=ob.a; }               // コピーコンストラクタ
  // 仮引数 ob に既存オブジェクトがコピーされます。(ob は後で消滅します。)
  // ob.a の値を、新しく構築するオブジェクトのメンバ a にコピーします。
  // メンバ関数は同じだからコピーする必要はありません。
          void func1() { cout << a << endl; } // 表示用のメンバ関数
};
class C2   // クラス C2 の宣言
{ public:
  void func2()
  { C1 OBa(5);     // クラス C1 のオブジェクト OBa を宣言 
    C1 OBb(OBa);   // OBa のコピー OBb を宣言 
    OB.func1();    // クラス C1 のメンバ関数を呼び出し(表示)
  }
};
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }

もし、コピーしたオブジェクトの一部のメンバだけを別な値にしたいときは、 次のように引数を追加して目的のメンバに代入を行います。
public: C1(C1 ob, int i) { a=ob.i; } // コピーコンストラクタ

上記の例は仮引数にオブジェクトを使用しています。
関数はオブジェクト全体を仮引数にコピーしてから仕事を始めるので、非効率的です。
次のように、参照を引数に使えば効率的なプログラムになります。
public: C1(&C1 ob) { a=ob.a; } // コピーコンストラクタ
// 参照は変数と同じように使用できるポインタですから、
// コンストラクタの呼び出しの書式は変数の場合と全く同じです。


T

C++言語 2 派生クラス 3 オブジェクト 4 フレンド・多重継承
 
  mtoga@sannet.ne.jp   登録日 '96. 6.15
URL : http://www.page.sannet.ne.jp/mtoga/index.html