クラス(class)

C++のクラス概念は,組み込みデータ型と同じように新しい型を作成する道具をプログラマに提供することを目的としている.また,派生クラスとテンプレートは,関連するクラスを構造化し,プログラマがその関係を利用できるようにしてくれる. コンピュータ科学でいう型とは,概念を具体的に表現したものである.例えば,C++の組み込みデータ型とそれが持つ+,-,*などの演算は,数学の四則演算の概念を具体化している.組み込みデータ型に直接対応していない概念を定義するために新しい型を提供するのがクラスである.つまり,クラスはユーザ定義型である.

クラスを理解するために,例として図形を考えよう.図形には色々あるが,例えば三角形を思い浮かべると,三角形には底辺と高さがあり,これによって面積が求まる.この三角形の属性である底辺と高さ,また,面積を求める方法などを1つのまとまりとしたものを三角形クラスという.このとき,底辺や高さをメンバ変数(データメンバ)といい,面積を求めるための方法をメンバ関数(メソッド)という.

この三角形クラスの宣言は,識別子classのあとにクラス名がきて,中括弧{から中括弧}までが本体となる.

クラス宣言(Class Declarations)

クラス宣言を用いて上の事柄を宣言すると次のようになる.

class Triangle
{
private:
    double base, height; //メンバ変数
public:
    void assign(double, double); //メンバ関数
    double area();
    void display();
};

ここで,classはクラス宣言を示すキーワードで,次のTriangleはこのクラスの名前である.{と}に囲まれた中は,クラスのメンバ変数とメンバ関数と呼ばれ,メンバどうしの名前が重複しなければ,どのような名前でも使える.また,クラスのメンバはディフォルトでは非公開 (private) メンバになる.したがって,クラスの外から参照する必要のあるコンストラクタやメンバ関数は公開(public)セクションの中におく必要がある. publicの後にはコロン:を必要とする. void display();はTriangleクラスに属するdisplay関数の宣言である.クラス宣言の最後は};で終わる.

このクラスをUML(unified modeling language)を用いて次のように表すことができる.

Triangle
base
height
assign()
area()
display()

クラスのオブジェクトを作る

メンバ関数display()は,その持ち主の名前をつけて,t.display()というように用いられる.
実際,メンバ関数はこのように用いるしかない.

オブジェクトtは普通の変数のように宣言される.この型はTriangleである.これはユーザ定義型(抽象データ型)として考えることができる.

C++では,int , float, doubleなどの型にTriangle型を付け加えることができる.これはオブジェクト t を次のように考えることで理解できる.

\begin{figure}\centering
\includegraphics[width=4.35cm]{CPPPIC/fig10-1.eps}
\end{figure}

また,オブジェクトtを宣言することを,オブジェクトのインスタンス化(instanciation)といい,オブジェクトtをTriangleクラスのインスタンスという.インスタンスとは,そのクラスの特定事例だと考えれば分かりやすい.

クラスを用いたプログラム

例題 10..1   三角形クラス
底辺18,高さ24.5の三角形の面積を求めるプログラムをTriangleクラスを用いて作成せよ.

解答

  1. Triangleクラスの宣言を行う.メンバ変数はbaseとheightとする.
  2. メンバ関数の定義を行う.メンバ関数の定義は
    戻り値のデータ型 クラス名::メンバ関数名()

    {
    }
    で行う.したがって,
    void Triangle::assign(double b, double h)  {
    base = b;
    height = h;
     }
    と定義できる.
  3. 最後にmain関数で,Triangleクラス型のオブジェクトを作り,三角形の面積を求める.

#include <iostream>
using namespace std;
class Triangle
{
    private:
        double base, height;
    public:
        void assign(double, double);
        double area();
        void display();
};

//メンバ関数の定義
void Triangle::assign(double b, double h)
{
    base = b;
    height = h;
}

double Triangle::area()
{
    return base*height/2;
}

void Triangle::display() //triangleに属するdisplay関数本体部分の定義
{
    cout << "三角形(" << base << "," << height << ")" << "の面積=" <<     area() << endl;
}

//main関数
int main ()
{
    Triangle t;
    t.assign(18,24.5);
    t.display();
}

実行結果

\begin{figure}% latex2html id marker 3191
\centering
\includegraphics[width=8.0cm]{CPPPIC/reidai10-1.eps}
\end{figure}

それぞれのメンバ関数の前にはクラス名であるTriangleを付ける.また,::によってメンバ関数はTriangleクラスのメンバであることを意味している.この::をスコープ解決演算子(scope resolution operator)という.

メンバ関数をクラスの中に含めて,

void assign(double, double) {base=b; height=t;}
のように書くこともできるが,あまり感心できるコーディングではない.一般にメンバ関数はクラス宣言の外に書くほうがよい.ただし,このテキストでは紙面の都合上,このような書き方を用いている.

例題10.1のように,メンバ関数がクラス宣言と別に定義されるとき,クラス宣言部分をインターフェイスといい,メンバ関数を含んでいる部分を実装部という.インターフェイス部分がプログラマーがそのクラスを使うときに見る部分で,普段,実装部は別のファイルに隠されている.これにより,情報隠蔽(information hiding)が可能になる.私たちはプログラムするとき,このクラスは何ができるのかを必要とするのであって,どのようにやるのかを知る必要はない.情報隠蔽はカプセル化(encapsulation)と呼ばれ,継承(inheritance)多態(polymorphism)と並んでオブジェクト指向プログラミングの3大重要概念の1つである.

練習問題 10..1   上の例題で,底辺が10,高さが20の三角形オブジェクトobj1を作成し,その面積を求めよ.

コンストラクタ(Constructors)

Triangleクラスはassign()メンバ関数を用いて,そのオブジェクトの初期化を行っている.しかし,オブジェクトが宣言されたときに,初期化するほうがより自然である.そこで,C++ ではクラスオブジェクトに対して,初期化が行えるようにコンストラクタメソッドを用意している.

コンストラクタはメンバ関数で,オブジェクトが宣言されると自動的に呼び出される.つまり,先ほどの例題でTriangle tで,Triangleクラスのオブジェクトtが作成されたが,実はコンストラクタが自動的に呼び出されたのである.コンストラクタは,クラスのオブジェクトを作る関数である.そのため,コンストラクタはクラスと同じ名前を取る.

例題 10..2   三角形クラス
底辺18,高さ24.5の三角形の面積を求めるプログラムをコンストラクタを用いて作成せよ.

解答

  1. Triangleクラスの宣言を行う.
  2. コンストラクタの定義を行う.コンストラクタの定義は
    クラス名::コンストラクタ名(型 引数)

    {
    }
    で行う.
  3. メンバ関数の定義を行う.メンバ関数の定義は
    戻り値のデータ型 クラス名:メンバ関数名()
    {
    }
    で行う.
  4. 最後にmain関数でTriangleクラス型のオブジェクトを作り,三角形の面積を求める.

#include <iostream>
using namespace std;
class Triangle
{
    private:
        double base, height;
    public:
        Triangle(double b, double h);
        double area();
        void display();
};

//コンストラクタの定義
Triangle::Triangle(double b, double h)
{
    base = b;
    height = h;
}

double Triangle::area()
{
    return base*height/2;
}

//display関数の定義
void Triangle::display()
{
    cout << "三角形(" << base << "," << height << ")" <<
    "の面積=" << area() << endl;
}

//main関数
int main ()
{
    Triangle t(18,24.5);
    t.display();
}

実行結果

\begin{figure}% latex2html id marker 3227
\centering
\includegraphics[width=8.0cm]{CPPPIC/reidai10-2.eps}
\end{figure}

コンストラクタはassign()と同じ働きをするばかりでなく,Triangle t(18,24.5)により,baseとheightを持つオブジェクトtが作成され,18と24.5がそれぞれbaseとheightに渡される.

Triangle t(18,24.5);は
    Triangle t;
    t.assign(18.24.5);
と同じである. さらに,
public:
    Triangle(double b, double h);//コンストラクタ

Triangle::Triangle(double b, double h)
{
    base = b;
    height = h;
}
をまとめて,次のように書くこともできる.

Triangle(double b, double h){base = b; height = h;}

また,
double area();
double Triangle::area()
 {
return base * height/2;
 }

をまとめて,

double area(){return base * height/2;}

と書くことができる.これを自動インライン化という.void display()も自動インライン化を行なうと,次のようになる.

#include <iostream>
using namespace std;
class Triangle
{
    private:
        double base, height;
    public:
        Triangle(double b, double h) {base = b; height = h;} //コンストラクタ
        double area() {return base*height/2;}
        void display() { cout << "三角形(" << base << "," << height << ")"
        << "の面積=" << area() << endl;}
};
//main関数
int main (void)
{
    Triangle t(18,24.5);//インスタンス化
    t.display();
}

練習問題 10..2   上の例題で,底辺が10,高さが20の三角形オブジェクトobj2をコンストラクタを用いて作成し,その面積を求めよ.

インライン(Inline)

inlineを用いると,次のように書くこともできる.C++の開発者Stroustrupはこの書き方を薦めている.

#include <iostream>
using namespace std;
class Triangle
{
    public:
        Triangle(double b, double h) {base = b; height = h;}
        double area();
        void display();
    private:
        double base, height;
};
inline double Triangle::area(){return base*height/2;}
inline void Triangle::display(){cout << "三角形(" << base << ","
<< height << ")" << "の面積=" << area() << endl;}
//main関数
int main ()
{
    Triangle t(18,24.5);
    t.display();
}

ここで,Triangleクラスとそのインスタンス化されたオブジェクトの関係を図で表すと次のようになる.

\begin{figure}\centering\includegraphics[width=10.6cm]{CPPPIC/fig10-2.eps}
\end{figure}
ここで,クラスは丸角矩形で表されメンバ関数を含んでいる.それぞれのメンバ関数はthisポインタを保持している.thisポインタは,呼んでいるオブジェクトを指している.この図は,上のプログラムの最後の行t.display()で何が起きているのかを表している.つまり,オブジェクトtがdisplay()関数を呼び出している.その瞬間,コンストラクタのthisポインタは呼ばれていないのでNULLである.

クラスは1つ以上のコンストラクタを持つことができる.

コンストラクタ初期化リスト(Constructor Initializing List)

ほとんどのコンストラクタはオブジェクトのメンバ変数を初期化するほか何もしない.そこで,C++にはこのコードを書くための特殊な記述法が用意してある.それには次のような初期化リスト(initialization list)を用いる.

base(b)
,
height(h)
{ }
1章ですでに学んだように,変数の初期化base(b);はbase = b;のことである.

関数へのオブジェクトの引渡し

関数に引数としてデータを渡すのと同じように,オブジェクトを引数として渡すことができる.それには,渡すオブジェクトの型を使用して関数の仮引数を宣言する.

例題 10..3   三角形クラス
底辺18,高さ24.5の三角形の面積と関数を利用して面積の2乗を求めるプログラムを初期化リストを用いて作成せよ.

解答 面積の2乗を求める関数をdouble sq();とし,その引数をTriangle tとする.このとき,面積はt.area()で求まる.

#include <iostream>
using namespace std;
class Triangle
{
    private:
        double base, height;
    public:
        Triangle(double b, double h) : base(b), height(h) {}
        double area();
        void display();
};

inline double Triangle::area(){return base*height/2;}
inline void Triangle::display(){cout << "三角形(" << base << ","
<< height << ")" << "の面積=" << area() << end }
void sq(Triangle t);\\
//main関数
int main ()
{
    Triangle t(18,24.5);
    t.display();
    sq(t);
}
void sq(Triangle t)
{
    double a = t.area();
    cout << "三角形の面積の2乗は" << a*a << endl;
}

実行結果

\begin{figure}% latex2html id marker 3258
\centering
\includegraphics[width=7.3cm]{CPPPIC/reidai10-3.eps}
\end{figure}

引数としてオブジェクトのポインタを使う

オブジェクトが沢山のメンバを持つときには,関数の呼び出しが遅くなる.そこで,このような時は,引数としてオブジェクトへのポインタを利用する.つまり,オブジェクトのアドレスを渡すので,メンバごとのコピーの必要がなくなる. これを達成するには,main()関数の中を,sq(&t);に,ユーザ関数を
void sq(Triangle* t)
{
double a = t $->$ area();
cout $<<$ "三角形の面積の2乗は" $<<$ a*a $<<$ endl;
}
とすればよい.

練習問題 10..3   底辺18,高さ24.5の三角形の面積と参照を利用して面積の2乗を求めるプログラムを作成せよ.

コピーコンストラクタ(The Copy Constructor)

どのクラスも少なくとも2つのコンストラクタを持っている.これらはその特別な表記によりすぐに見分けることができる.

X( ); // ディフォルトのコンストラクタ
X(const X&); // コピーコンストラクタ
これは,コンストラクタ関数のオーバーロードである.ここで,Xが上のTriangleクラスなら,ディフォルトコンストラクタは
Triangle( );
で,コピーコンストラクタは
Triangle(const Triangle&);
となる.ディフォルトコンストラクタは,オブジェクトの宣言
Triangle x;
が行われたときによばれる.また,コピーコンストラクタは,次のようにオブジェクトがコピーされたときによばれる.
Triangle y(x);
これらのコンストラクタが定義されていなければ,これらのコンストラクタは暗黙のうちにシステムにより宣言される.ここで注意して欲しいのは,コピーコンストラクタはオブジェクトをコピーするために1つの引数をとる.この引数,const Triangle&のconstはオブジェクトがメンバ関数により変更されないことを意味する.そして,そのオブジェクトは定数の参照で渡される.コピーコンストラクタがよばれると,オブジェクトを完全な状態で同じクラスの新しいオブジェクトにコピーする.もし,クラスの定義がこれまでの例題のように,明示的にコピーコンストラクタを含んでいないときには,システムはディフォルトで作成する.つまり,自分で自分のコピーコンストラクタを作成する.

例題 10..4   コピーコンストラクタ
2次元のPointクラスを実装せよ.ただし,ディフォルトコンストラクタ,コピーコンストラクタ,アクセス関数norm(),print()関数を含むものとする.

解答

#include <iostream>
#include <cmath>
using namespace std;
class Point
{
    private:
        double _x, _y;
    public:
        Point(1) : _x(0), _y(0) {}
        Point(double x, double y) : _x(x), _y(y) {}
        Point(const Point& P) : _x=P._x,-y=P._y {}
        Triangle(const Triangle& t) : base(t.base), height(t.height)
        {
               cout << "コピーコンストラクタがよばれた" << endl;
        }
        double area() {return base*height/2};
        void display() {cout << "三角形(" << base << "," << height << ")"
        << "の面積=" << area() << endl;}
};
int main ()
{
    Triangle x(18,24.5);
    Triangle y(x);
    y.display();
}

実行結果

\begin{figure}% latex2html id marker 3286
\centering
\includegraphics[width=8.0cm]{CPPPIC/reidai10-4.eps}
\end{figure}

練習問題 10..4   中心の座標(x,y)と半径radiusをもつCircleクラスを作成せよ.ただし,このクラスはディフォルトコンストラクタとアクセス関数area()を含むものとする.

クラスディストラクタ(Class Destructor)

オブジェクトの生成には,自動的にコンストラクタが関わる.同様に,オブジェクトが消滅するときには,ディストラクタ(destructor)が関わる.

すべてのクラスには1つのディストラクタがある.もし,クラスの中で明示的に定義してなければ,ディフォルトコンストラクタ,コピーコンストラクタ,代入演算子のように自動的に作成される.

クラスディストラクタは,オブジェクトがスコープの最後に到着すると呼ばれる.

クラスディストラクタはコンストラクタの前に〜をつけることにより作成する.

定数オブジェクト(Constant Objects)

オブジェクトが変更されるべきでないときは,定数として宣言しておくのがよいプログラミング技法である.これを行うには,識別子constを用いる.

const char BLANK = ' ';
const int MAX_INT = 2147483647;
const double PI = 3.141592653589793;
void init(float a[], const int SIZE);
変数や関数引数と同様,オブジェクトも定数とし宣言できる.
const Ratio PI(22,7);
しかし,このときC++コンパイラはオブジェクトのメンバ関数へのアクセスを制限する.例えば,Ratioクラスにおいてprint()関数はこのオブジェクトから呼ぶことはできない.つまり,
PI.print();
はエラーとなる.

実際,Ratioクラスの定義を変更しないかぎり,定数オブジェクトから呼ぶことができるメンバ関数はコンストラクタとディストラクタだけである.この問題を解決するには,定数オブジェクトから呼ばれるメンバ関数を定数として宣言しておくことである.つまり,

void print() const {cout << num << '/' << den << endl;}
とすればよい.これにより,
const Ratio PI(22,7);
PI.print();
として定数オブジェクトPIからメンバ関数print()を呼ぶことができる.

動的にオブジェクトを作成する

Xがクラスのとき,X x;でxはクラスX型のオブジェクトになる.また,X* p = new X;により,pはX型へのポインタである.つまり,オブジェクトを動的に作成してポインタにアドレスを代入する.よって,*pはX型のオブジェクトである.ここで,dataがクラスXの公開メンバ変数なら,(*p).dataによりその公開メンバ変数dataにアクセスすることができる.ここで, 2つの表記
(*p).data
p -$>$ data
は全く同じ意味を持っている.ポインタを用いているときは,記号-$>$を用いるのが一般的である.さらに,アロー演算子(-$>$)は指し示すものと読めば分かりやすいという特徴も持っている.

例題 10..5   dataのアクセス
次のクラスXの公開メンバ変数dataを,ポインタを用いる方法と用いない方法でアクセスするプログラムを作成せよ.

解答

#include <iostream>
using namespace std;
class X
{
    public:
        int data;
};
int main()
{
    X* p = new X;
    (*p).data = 22;
    cout << "(*p).data = " << (*p).data << endl;
    p-> data = 44;
    cout << "p -> data = " << p -> data << endl;
}

実行結果

\begin{figure}% latex2html id marker 3314
\centering
\includegraphics[width=7.0cm]{CPPPIC/reidai10-5.eps}
\end{figure}

データ構造(Data Structures)

データ構造の1つにリストと呼ばれるものがある.リストには線形リスト(linear list)連結リスト(linked list)と呼ばれるものがある.線形リストとは,同じ要素が順番に並んでいる構造をいう.線形リストの代表的なものに配列がある.

連結リストは,同じ要素がポインタによって,数珠のようにつながっている構造をいう.連結リストには,単方向リストといい,次のデータのポインタだけを持つもの,双方向リストといい,前と次のデータへのポインタを持つもの,環状リストといい,データが環状に連結されているもの,後入れ先出しリスト(LIFO)といい,後から入れたデータが先に取出されるもの,すでに学んだスタックがこれにあたる.そして,先入れ先出し(FIFO)リストといい,先に入れたデータを先に取り出されるものとがある.キューがこれにあたる.

連結リストの基本は自己参照クラスとポインタである.連結リストの要素は,一般にノード(node)またはセル(cell)とよばれ,自己参照クラスで表現される.
class Node
{
public:
Node(int d, Node* q = 0) : data(d), next(q) { }
int data;
Node* next // 自己参照クラス
};
これにより,Nodeクラスのオブジェクトは,int dataメンバとnextポインタノードを含んでいる.ここで,Nodeクラスの定義はクラス自身への2つの参照を含んでいる.これは,それぞれの参照がクラスへのポインタであることから許されている.また,コンストラクタが両方のメンバ変数を初期化していることにも注意して欲しい.

例題 10..6   連結リストのノードクラス
12 23 34 45 56 67 ${}^{\wedge}$Dと入力したら,
67 -$>$ 56 -$>$ 45 -$>$ 34 -$>$ 23 -$>$ 12 -$>$ *と表示するプログラムを作成せよ.

解答 上の説明で,連結リストを作成するためのNodeクラスを定義した.Nodeクラスはデータを格納するメンバ変数dataと次のNodeを指すメンバ変数nextを持っている.そこで,ファイルの終端文字 ${}^{\wedge}$Dが入力されるまでwhileループによりメンバ変数nに整数を読み込む.そして,新しいノードを取り込み,メンバ変数pに整数を挿入する.

forループはリストpが指しているノードからはじめ,pがナルになるまで全探索する.キーボードから67が最後に入力されれば,pを指しているノードは67を含んだノードとなる.

この例題で作成されるリストは次のように考えることができる.

\begin{figure}\centering
\includegraphics[width=13.9cm]{CPPPIC/fig10-8.eps}
\end{figure}

#include <iostream>
using namespace std;
class Node
{
    public:
        Node(int d, Node* q=0) : data(d), next(q) { }
        int data;
        Node* next; // 自己参照クラス
};
int main()
{
    int n;
    Node* p;
    Node* q=0;
    while(cin >> n){
        p = new Node(n,q);
        q = p;
    }
    for (; p; p=p-> next){
        cout << p-> data << " -> ";
    }
    cout << "*\n";
}

実行結果

\begin{figure}% latex2html id marker 3348
\centering
\includegraphics[width=8.8cm]{CPPPIC/reidai10-6.eps}
\end{figure}

静的メンバ変数(Static Data Member)

メンバ変数の1つの値がクラスの全てのメンバ変数に適応されることがある.このような場合,全てのメンバ変数に同じ値を格納しておくのは効率的ではない.そこで,このことを防ぐ方法として,メンバ変数をスタティック(static)で宣言しておく方法がある.その構文は次のようになる.
class X
{
static int n; // nを静的データとして宣言
};
int X::n = 0; // nの定義

静的メンバ変数は自動的に初期化される.したがって,最後の行は零以外の初期値を必要とするとき以外,書いても書かなくてもよい.

例題 10..7   静的メンバ変数
ThingamabobクラスはThingamabobオブジェクトの数を数えるための静的メンバ変数 countを保持している.Thingamabobオブジェクトが生成されるとカウンタは増え,Thingamabobオブジェクトが消滅するとカウンタは減る.

#include <iostream>
using namespace std;
class Thingamabob
{
    public:
        Thingamabob() {++count;}
       ~Thingamabob() {--count;}
        static int count;
};
int Thingamabob::count=0;

int main()
{
    Thingamabob w, x;
    cout << "Now there are " << w.count << " Thingamabobs." << endl;
    {
        Thingamabob w,x,y,z;
        cout << "Now there are " << w.count << " Thingamabobs." << endl;
    }
    cout << "Now there are " << w.count << " Thingamabobs." << endl;
    Thingamabob y;
    cout <<< "Now there are " << w.count << " Thingamabobs." << endl;
}

最初に2個のThingamabobが作られ,次に内側のブロックで4つのThingamabobが生成され全部で6個になるが,プログラムコントロールがそのブロックを去るとき消滅してまた2個に戻っている.

静的メンバ変数は大域変数のように,インスタンスの数に関わらず1つのコピーしか持たない.大域変数との違いは,関数なので非公開.

実行結果

\begin{figure}% latex2html id marker 3367
\centering
\includegraphics[width=7.8cm]{CPPPIC/reidai10-7.eps}
\end{figure}

例題 10..8   非公開の静的メンバ変数

#include <iostream>
using namespace std;

class Thingamabob
{
    public:
        Thingamabob() {++count;}
        ~Thingamabob() {--count;}
        int numThingamabobs() {return count;}
    private:
        static int count;
};
int Thingamabob::count=0;

int main()
{
    Thingamabob w, x;
    cout << "Now there are " << w.numThingamabobs() << " numThingamabobs." << endl;
    {
        Thingamabob w,x,y,z;
        cout << "Now there are " << w.numThingamabobs() << " numThingamabobs." << endl;
    }
    cout << "Now there are " << w.numThingamabobs() << " numThingamabobs." << endl;
    Thingamabob y;
    cout << "Now there are " << w.numThingamabobs() << " numThingamabobs." << endl;
}

この例題では,静的メンバ変数countが非公開である.したがって,countにアクセスするにはアクセス関数 numThingamabob()が必要である.

実行結果

\begin{figure}% latex2html id marker 3377
\centering
\includegraphics[width=7.8cm]{CPPPIC/reidai10-8.eps}
\end{figure}

静的メンバ関数(Static Member Functions)

メンバ関数を staticで宣言すればよい.

例題 10..9   静的メンバ関数
ThingamabobクラスはThingamabobオブジェクトの数を数えるための静的メンバ変数 countを保持している.Thingamabobオブジェクトが生成されるとカウンタは増え,Thingamabobオブジェクトが消滅するとカウンタは減る.

#include <iostream>
using namespace std;
class Thingamabob
{
    public:
        Thingamabob() {++count;}
    ~Thingamabob() {--count;}
        static int num() {return count;}
    private:
        static int count;
};
int Thingamabob::count=0;

int main()
{
    cout << "Now there are " << Thingamabob::num() << " Thingamabobs." << endl;
    Thingamabob w, x;
    cout << "Now there are " << Thingamabob::num() << " Thingamabobs." << endl;
    {
       Thingamabob w,x,y,z;
       cout << "Now there are " << Thingamabob::num() << " Thingamabobs." << endl;
    }
    cout << "Now there are " << Thingamabob::num() << " Thingamabobs." << endl;
    Thingamabob y;
    cout << "Now there are " << Thingamabob::num() << " Thingamabobs." << endl;
}

実行結果

\begin{figure}% latex2html id marker 3387
\centering
\includegraphics[width=7.8cm]{CPPPIC/reidai10-9.eps}
\end{figure}

確認問題 10..1  

1. クラスの公開メンバと非公開メンバとの違いを説明せよ.

2. クラスメンバ関数とアプリケーション関数との違いを説明せよ.

3. ディフォルトコンストラクタとそれ以外のコンストラクタとの違いを説明せよ.

4. C++におけるclassとstructとの違いを説明せよ.

5. コンストラクタにはどんな名前を付けることができるか.また,ディストラクタにはどんな名前を付けることができるか.

6. 1つのクラスには何個のコンストラクタとディストラクタを含むことができるか.

7. 次のコードでコピーコンストラクタは何回呼ばれたか.

Thingamabob f(Thingamabob u)

{

Thingamabob v(u);

Thingamabob w = v;

return w;

}

int main()

{

Thingamabob x;

Thingamabob y = f(f(x));

}

演習問題 10..1  

1. 空間上の点(x,y,z)からなるPointクラスを作成せよ.ただし,このクラスは,ディフォルトコンストラクタ,コピーコンストラクタ,点の座標を負にするnegate()関数,距離を表すnorm()関数,そして表示のためのprint()関数を含むとする.

2. 整数のスタックのStackクラスを作成せよ.ディフォルトコンストラクタ,ディストラクタ,push(), pop(), isEmpty(), isFull()関数を含むものとする.

\begin{figure}\includegraphics[width=5.7cm]{CPPPIC/stack.eps}
\end{figure}