next up previous
Next: 継承(インヘリタンス) Up: オブジェクト指向っぽいC++ Previous: クラス定義

コンストラクタとデストラクタ

画面上の点を定義するときに,上述のようなPoint::set() を使って

Point p;
p.set(10,20);
としてもよいが,Pointのインスタンスが生成された時点で, まだ実際の画面上の点に対応していないというのが気持ち悪い. Pointのインスタンスが生成されると同時に画面上の点と 対応がついてくれた方が何かと好都合だ.C++では,インスタンスが 生成されるときに,その初期化をする関数を定義することができる. このような関数をコンストラクタと呼ぶ.コンストラクタは, クラスの名前と同じ名前を持つ.こんな感じだ.
class Point {
  private:
    ....
  public:
    Point(int x, int y, int col) { 
        color = col;
        set(x,y);
    }
    ....
};
コンストラクタはインスタンスの初期化だけを行うので,返値をもたない (voidですらない).したがって,返値の型の宣言はない.上記のように コンストラクタを宣言した場合,Pointのインスタンスの宣言は,
Point p(10,20,1);
のようにする.また,newを使ってPointのインスタンスを 生成するときは,
Point *p = new Point(10,20,1);
のように記述する. コンストラクタも関数の一種なので多重定義が可能であり,引数の デフォルト値なども使うことができる.

Pointのインスタンスが消滅するときは,画面上の点にも消えてもらわないと 都合が悪い.C++では,このようなインスタンスが消滅するときの 処理も書くことができる.このような処理を記述する関数をデストラクタと呼ぶ. デストラクタは,クラス名の頭にがついた名前を持つ. こんな感じだ.

class Point {
  private:
    ....
  public:
    ‾Point() { 
        draw_point(coord.x, coord.y, 0);
    }
    ....
};
ここで,0という色は背景色のつもりである.デストラクタの宣言には コンストラクタの場合と同じく返値の型はなく,またデストラクタの場合は 引数がない.

Pointのインスタンスに対してデストラクタが呼ばれるのは, 次のような場合だ.

このように,コンストラクタとデストラクタを使うと, データの初期化や後始末が自動的にできる.ただ, ちょっと注意が必要なのは,他のクラスのメンバとして Pointなどのクラスを使う場合だ. 例えば

class TwoPoints {
  private:
    Point p1;
    Point p2;
  public:
    TwoPoints() {...}
};
のようなクラスを作った場合,p1, p2のコンストラクタを TwoPoints()のどこかで呼ばなければならない (呼ばないとエラーになるはずだ). それには,こんな風に記述する.
class TwoPoints {
  private:
    Point p1;
    Point p2;
  public:
    TwoPoints() :p1(0,0,1), p2(10,10,1) {...}
};
TwoPoints()のコンストラクタの本体が呼ばれる前に, その各メンバのコンストラクタを呼ぶわけだ.これは場合によっては 不便なこともあるが,言語仕様なので仕方がない.ちなみに,メンバが PointでなくPoint*の場合,newを使って こんな風にかける.
class TwoPoints {
  private:
    Point *p1;
    Point *p2;
  public:
    TwoPoints() {
        p1 = new Point(0,0,1);
        p2 = new Point(10,0,1);
        ...
    }
};
newを使ってメンバを確保したときは,デストラクタの中で それらをdeleteした方が良い.こんな感じだ.
class TwoPoints {
  private:
    Point *p1;
    Point *p2;
  public:
    TwoPoints() {
        p1 = new Point(0,0,1);
        p2 = new Point(10,0,1);
        ...
    }
    ‾TwoPoints() {
        delete p1;
        delete p2;
    }
};

コンストラクタに関して,もう一つ注意がある.Point の配列を作りたい場合,

Point p[100];
このようなことをするためには,クラスPointで引数のない コンストラクタが定義されていなければならない.つまり
class Point {
  ...
  public:
  Point() { ... }
};
というコンストラクタがないとだめだ,というわけである.クラスの 配列を取ったとき,その配列の各要素について,引数のないコンストラクタ が呼ばれる.



Akinori ITO
Thu Aug 7 15:05:13 JST 1997