ところで、「値を戻す」ということは、クラスのメンバ関数でない関数でも同じです。説明を簡単にするため,まず、そのような関数を考えることにしましょう。下のプログラムをみてください。
//ex1.cpp
#include <iostream>
using namespace std;
//関数func()を定義します。
void func()
{
cout << "こんにちは。私はコンピュータです。"
<< endl;
}
int main()
{
func(); //funcを使っている。
}
少し見慣れない形式ですね。上のプログラムでは、まず関数func()を定義しているのです。関数と言ってもただ「こんにちは。私はコンピュータです。」と画面に表示するだけの関数です。このようにクラスとは何の関係もない関数を定義することもできるのです。このような関数を一般に、グローバル関数などといいます。
そして、mainの中に「func();」と書いてありますが、ここで関数funcを実行しているのです。(つまり、こう書くと、関数funcを実行できるわけです。)ただし、ここではvoidを書きません。というのは、voidがいるのは関数を宣言したり定義するときだけだからです。mainのなかにある「func();」は関数func使っているだけで、宣言や定義ではないため、voidはいらないのです。念のため。
上のプログラムを、実行して確かめてみてください。これは、funcを実行するだけ、つまり、「こんにちは。私はコンピュータです。」と画面に表示するだけのプログラムなのです。
Fig.1 ex1.exe
どうしてこんなめんどうなことをするのだろうと思いましたか?「cout
<< "こんにちは。私はコンピュータです。" << endl;」を直接mainの中に書けば終わりなのにと思った人、あなたのプログラムの能力は着実に向上しています。しかし、もっと複雑なプログラムの場合、このように関数を定義することは重要です。なぜでしょう。それは、「関数もクラスのようにプログラムの部品となり得るからだ」と考えた人、あなたはこの講義をパーフェクトに理解しています。あまりに簡単な例なのでピンとこないかもしれませんが、そういうわけなのです。
さて、ここで、上のプログラムを次のように変えてみます。
//ex2.cpp
#include <iostream>
using namespace std;
//関数func()を定義します。
int func()
{
cout << "こんにちは。私はコンピュータです。"
<< endl;
return 1; //整数値1を戻す
}
int main()
{
func(); //func()を使っている。
}
//ex3.cpp
#include <iostream>
using namespace std;
//関数func()を定義します。
int func()
{
cout<<"こんにちは。私はコンピュータです。"<<endl;
return 1; //整数値1を戻す
}
int main()
{
int d; //整数変数dの宣言(「整数dを使うよ」という意味)
d = func(); //考え込むと不思議な文ですが、次のような意味になります。
//まず、func()の中身が実行される。
//そして、この関数から戻された値1がdに代入される。
cout << "func()から戻された値=" <<
d << endl;
//dの値を出力
}
ここで、「d = func();」はなんとも不思議な文ですが、これで、func()の中身がまず実行され、次に値1が戻され、それがdに代入されることになるのです。ここでいう「戻される」とは、実質的には、この関数func()が実行されたあと、func()と書いてあるところが数値1に変わるということなのです。
実際実行してみてください。まず、画面に「こんにちは。私はコンピュータです。」と出力され、その後に(と言っても,人間の目にその順序は見えませんが)数値1が画面に出力されて終わりになります。
Fig.2 ex3.exe
ex2.cppとex3.cppの違いは、単に、戻された値を使うか使わないかの違いです。このように戻された値を使う使わないはプログラマの自由なのです。
上の例はあまりにも無意味な例だったので、「二つの整数値をきいて、その合計を戻す」関数をつくって、その関数を使うプログラムを書いてみましょう。
//tasizan.cpp
#include <iostream>
using namespace std;
//足し算をする関数
int add()
{
int a, b; //二つの整数をいれる変数
cout << "これから二つの整数の足し算をします。"
<< endl;
cout << "まず、ひとつめの整数を入力してください。"
<< endl;
cin >> a;
cout << "もうひとつの整数を入力してください。"
<< endl;
cin >> b;
//次のreturnで合計を戻す
return a + b;
}
int main()
{
int d = add(); //整数変数dが宣言され、すぐにadd()が実行され、その戻す値がdに代入される。
cout << "合計:" << d << endl;
}
Fig.3 tasizan.exe
この例のように、戻り値は定数である必要はないのです。
それでは、初心者には少し難しい問題をひとつ。できなくても大丈夫です。とても熱心な人は今までの復習をしながら考えてみてください。それほど熱心でもない普通の人は、ちょっと考えてから、答えを眺めてみてください。
問題:
入門5の猫を次のように改良したクラスをつくってください。
クラス 猫
データメンバ:名前
体力(整数)
メンバ関数 :コンストラクタ(名前を受け取り、はじめの体力を10とする)
食事をもらう(もらってたべた量だけ体力を増やす関数)
鳴く(鳴いて、体力を5減らす)
ただし、関数「食事」と「鳴く」は実行後の体力を「戻り値」で報告するものとします。
解答例:
class Neko
{
string name; //名前
int tairyoku; //体力
public:
Neko(string n) : name(n), tairyoku(10){}
int syokuji(); //食事を(ユーザから)もらう関数
int naku(); //鳴く関数
};
int Neko::syokuji(){
cout << name << "に食事をさせます。どれだけ食べさせますか?"
<< endl;
cout << "半角の数字で入力してください。"
<< endl;
int food;
//食べさせる量 ユーザに決めてもらう
cin >> food;
tairyoku += food;
return tairyoku; //tairyokuの値を戻す
}
int Neko::naku()
{
cout << "にゃあ。俺様は" << name
<< "だ。" << endl;
tairyoku -= 5;
return tairyoku; //tairyokuの値を戻す
}
「tairyoku += food;」は「tairyokuにfoodを足せ」、「tairyoku
-= 5;」は「tairyokuから5引け」という意味でしたね。ポイントはコンストラクタを除く関数の前にintがあり、それらの定義の最後にはreturn文があるということです。
このクラスを使ったプログラム例は次のようなものでしょう。
//neko4.cpp
#include <iostream>
#include <string> //stringを使うために必要
using namespace std;
class Neko
{
string name; //名前
int tairyoku; //体力
public:
Neko(string n) : name(n), tairyoku(10){}
int syokuji(); //食事を(ユーザから)もらう関数
int naku(); //鳴く関数
};
int Neko::syokuji(){
cout << name << "に食事をさせます。どれだけ食べさせますか?"
<< endl;
cout << "半角の数字で入力してください。"
<< endl;
int food; //食べさせる量 ユーザに決めてもらう
cin >> food;
tairyoku += food;
return tairyoku; //tairyokuの値を戻す
}
int Neko::naku()
{
cout << "にゃあ。俺様は" << name
<< "だ。" << endl;
tairyoku -= 5;
return tairyoku; //tairyokuの値を戻す
}
int main()
{
cout << "猫をメモリ上に生成します。名前を決めてください。"
<< endl;
string temp;
cin >> temp;
Neko kai_neko(temp); //飼い猫の生成 名はユーザがtempに入力したもの
cout << endl;
for(int i = 0; i < 5 ;i++){ //5回だけメモリ上の猫と遊ぶプログラムです
cout << "どうします?"
<< endl;
cout << "1
食事を与える 2 鳴かす" << endl;
cout << "半角の数字で入力してください。"
<< endl;
int ans;
cin >> ans;
if(ans == 1){
int t;
t =
kai_neko.syokuji(); //まず、Neko::syokujiの内容が実行され、その結果の体力が
//Neko::syokujiの戻り値として与えられ、tに代入される。
cout <<
"猫の体力=" << t << endl;
}
else if(ans == 2){
int t;
//上のtとは別の{ }ブロック内にあるので全く無関係
t =
kai_neko.naku(); //まず、Neko::nakuの内容が実行され、その結果の体力が
//Neko::nakuの戻り値として与えられ、tに代入される。
cout <<
"猫の体力=" << t << endl;
if(t < 0){
cout << "食事が不十分だったので、猫は隣のお金持ちの家に行ってしまいました。"<<endl;
break; //for文からぬけろという命令 体力が負になったらおしまいということです
} //if(t<0)のかっこ閉じる
} //if(ans==2)のかっこ閉じる
cout << endl; //見やすさのための改行
} //for(i=0;i<5;i++)のかっこ閉じる
cout<<"おわり"<<endl;
}
Fig.4 neko4.exe
ところで、気が付いていましたか?mainもよく見ると、関数の定義と同じ形をしていますね。
int main()
{
...
}
実は、mainは、プログラムの中心を表わすグローバル関数なのです。そして、mainの前にintを書くのは、この関数はintを戻すように、決められているからなのです。
そして、一般に(慣習的に)、mainは、プログラムが正常終了したところで0を戻すことになっています。そのため、mainの最後に「return
0;」と書くのが「正式」なのです。ただし、C++では、mainの最後に何も書かなければ、自動的にそこに「return
0;」があることになるのです。つまり、いつも書くことなので、省略してもよいことになっているのです。そのため、この入門では、mainの最後に「return
0;」を書いていないのです。しかし、それにしても、「mainはintを戻す関数」ということはおぼえておきましょう。