第1章 第5節 分業のススメ、関数のお話


← 前に戻る | 次に進む →

さて、ここまでのプログラムはすべてmain関数だけを使用してきました。しかし、ちょっと大き目のプログラムを組もうとするだけで、非常に長い関数になってしまうことはすぐにわかるでしょう。

そこで、プログラムをそれぞれの役割ごとに分業させましょう。それには関数を作るところから始まります。第4節のList 1.11のプログラムを関数を使用して書き直したものが、以下に示すプログラムになります。

List 1.12 簡易こづかい帳 関数版 (宣言と定義が別)

#include <iostream>
using namespace std;

bool Cashbook(int&);

int main()
{
    const int max_count = 20;
    int total;

    total = 10000;
    cout << "現在の所持金は " << total << " 円になります。" << endl;

    // (max_count)回まで記録を付けられます.
    for (int i = 0; i < max_count; i++) {
        if (Cashbook(total)) break;
    }

    cout << "現在の所持金は " << total << " 円になります。" << endl;

    return 0;
}

bool Cashbook(int& total)
{
    int income, outgo;
    int sw;

    cout << "収入なら 1、支出なら 2、それ以外なら終了です: " << ends;
    cin >> sw;

    switch (sw) {
    case 1:
        cout << "収入はいくらですか? " << ends;
        cin >> income;
        total += income;
        break;
    case 2:
        cout << "支出はいくらですか? " << ends;
        cin >> outgo;
        total -= outgo;
        break;
    default:
        return true;
    }

    return false;
}


現在の所持金は 10000 円になります。
収入なら 1、支出なら 2、それ以外なら終了です:  1
収入はいくらですか?  3000
収入なら 1、支出なら 2、それ以外なら終了です:  2
支出はいくらですか?  5000
収入なら 1、支出なら 2、それ以外なら終了です:  2
支出はいくらですか?  2000
収入なら 1、支出なら 2、それ以外なら終了です:  0
現在の所持金は 6000 円になります。

これは、ユーザとの対話部分をCashbookという関数にして、書き直したものです。因みに、関数とは、プログラムのうちで名前がついていて、必要に応じて何度でもプログラムの他の部分から起動することができる部分であり、戻り値と引数を持っています。つまり、ここではCashbookという名前で、戻り値にbool型、引数にint&型を一つ持つ関数ということになります。

ところで、関数は変数のように、宣言をしなくてはなりません。ここでは、最初にbool Cashbook(int&);と宣言をしています。そして、この後にその中身の記述、つまり定義を行わなければならないわけです。

しかし、呼び出しを行っている関数(例ではmain関数)の前で呼び出される関数(例ではCashbook関数)を定義することで、この宣言と定義を一緒にしてしまうこともできます。それが次に示すプログラムです。

List 1.13 簡易こづかい帳 関数版 (宣言と定義が一緒)

#include <iostream>
using namespace std;

bool Cashbook(int& total)
{
    int income, outgo;
    int sw;

    cout << "収入なら 1、支出なら 2、それ以外なら終了です: " << ends;
    cin >> sw;

    switch (sw) {
    case 1:
        cout << "収入はいくらですか? " << ends;
        cin >> income;
        total += income;
        break;
    case 2:
        cout << "支出はいくらですか? " << ends;
        cin >> outgo;
        total -= outgo;
        break;
    default:
        return true;
    }

    return false;
}

int main()
{
    const int max_count = 20;
    int total;

    total = 10000;
    cout << "現在の所持金は " << total << " 円になります。" << endl;

    // (max_count)回まで記録を付けられます.
    for (int i = 0; i < max_count; i++) {
        if (Cashbook(total)) break;
    }

    cout << "現在の所持金は " << total << " 円になります。" << endl;

    return 0;
}


現在の所持金は 10000 円になります。
収入なら 1、支出なら 2、それ以外なら終了です:  1
収入はいくらですか?  3000
収入なら 1、支出なら 2、それ以外なら終了です:  2
支出はいくらですか?  5000
収入なら 1、支出なら 2、それ以外なら終了です:  2
支出はいくらですか?  2000
収入なら 1、支出なら 2、それ以外なら終了です:  0
現在の所持金は 6000 円になります。

基本的にはどちらを使っても間違いではありませんが、プログラムが大きくなればなるほど、宣言と定義は分けておいたほうが良いでしょう。プログラムが大きくなるとファイルごとに分割されることが多くなるので、宣言部分を別のファイルにしておけば、そのファイルをインクルードするだけで済むようになるからです。ファイルを分割することがないような短いプログラムなどでは、宣言と定義が一緒でも良いでしょう。

ではプログラムの中身を見てきます。

動作自体は第4節のList 1.11とまったく変わっていません。まずは、for文で20回繰り返す部分を見てみましょう。あれれ? 20回繰り返すはずなので、for文の中でi < 20;と記述されているかと思いきや、i < max_count;なんて、記述されています。これは、もし20回でなく、30回繰り返したくなったりしても、すぐに修正できるようにしたわけです。で、そのmax_countの宣言部分を見てみるとconst int max_count = 20;のように、ちゃんとmax_countに20が代入されていますね。

ところで、このconstは初めて出てきましたが、これは定数を意味するキーワードです。つまり、値が変えられる変数ではなく値が固定の定数にするわけです。よって、このmax_countはこの宣言以降で変更されることはありません。よって、constキーワードは、プログラム中で後で変更されることのない名前付きの数値として扱いたいときに使用すると良いでしょう。

次に、この節のメインである関数の部分について見ていくことにしましょう。

まずこのプログラムで宣言されている関数は、Cashbookという名前で、戻り値にbool型、引数にint&型が使われています。どちらも、今までに出てきていませんので簡単に説明します。

bool型は、真偽値を表す型で、trueとfalseの二値を持っています。それぞれ、真と偽を表します。

真偽値について

真偽値の取り扱いは、注意を要します。特にint b; ... if (b == true) ...;などのように、int型の数値などを使用したときに(C言語のBOOLマクロなども同じです)このような==を用いた比較を行うのは危険なことです。CおよびC++では、0以外は真であり、0は偽であるという規則があるので、ここでもし、bに2などの数値が入っていた場合、真であるのに偽であると判断されてしまうことになります。よって、真偽値を取り扱うときは、必ずif (b) ...;のように(偽であったらif (!b) ...;)、比較を使わずに書くように気を付けましょう。因みにC++では、このときbに暗黙の型変換が起こり、int型からbool型に変換されています。

そして、int&型はリファレンスといって、型の最後に&をつけることによって、ある型のエイリアスとして使用できます。つまり、以下に示すプログラムのように、ある変数の別名を使用することができるのです。

List 1.14 リファレンスの例

#include <iostream>
using namespace std;

int main()
{
    int a;
    int& b = a;  // bはaのエイリアス.

    b = 100;

    cout << "a : " << a << endl;
    cout << "b : " << b << endl;

    return 0;
}


a : 100
b : 100

このプログラムの場合、aの別名にbを使っています。よって、bを変更すればaの値も変更されるのです。

値渡しと参照渡し

C言語は、関数の仮引数に値を渡すやり方として、値渡ししか持っていません。参照渡しに見せかけるためにポインタを使用できますが、それもポインタの値渡しということになります。C++では、値渡しのほかに、参照渡し(リファレンス渡し)ができるようになりました。これによって、ポインタなどを介さなくてもよくなり、読みやすく、しかも効率よくプログラムを組めるようになったのです。C++はクラスなどにより、大きなオブジェクトを使用することが多いので、リファレンスは必須なものとなっています。

では、もとに戻って、Cashbook関数の引数を見てみましょう。この引数はリファレンス型なので、この関数に渡された変数は、この関数内で変更された場合、この変数を渡した側も一緒に変更されます。具体的にいえば、main関数内で使われているtotal変数がCashbook関数に渡され、その渡されたtotal変数が変更された場合、main関数のtotal変数も一緒に変更されるということになります。

Cashbook関数の中身はList 1.11のプログラムのfor文内とほとんど一緒ですが、戻り値として、bool型が使われているので、その値を返すのにreturn文が使われています。そして、trueが返されるとmain関数内のfor文を抜けて、プログラムの終了となります。


← 前に戻る | 次に進む →


Copyright (C) Noriyuki Futatsugi/Foota Software, Japan.
All rights reserved.
d2VibWFzdGVyQGZ1dGF0c3VnaS5uZXQ=