===== 構造化プログラミングとオブジェクト指向と ===== これまで、C++のごくごく基礎的なところを学んできました。\\ C++はC言語の仕様を「ほぼ」まるっと含んでしまっているので、C++のいいところだけを使ってC言語を拡張しただけの形でソースコードを記述することができます。\\ このように、C言語の構造化プログラミング手法をそのまま使って、C++の機能の使いやすいものだけを使って書く手法を「better C」と呼んだりします。\\ これまでやってきたものが、だいたいbetter Cの状態です。\\ これまでの手法でも、わりとC++のおいしいところはいただけたのですが、今後はもっとC++の高度な機能を学んでいこうではないかと思います。\\ ===== オブジェクト指向(Object oriented Programing) ===== オブジェクト指向は、これまで処理ベースで関数として仕事を切り分けていくというプログラムの組み立て方をしてきたのですが、これを「対象(オブジェクト)の性質を抽象化」することでプログラムを組み立てていく手法になります。(=難しくて意味わかりません)\\ 違いを見るために、とりあえず今までの手法をまとめてみましょう。 ==== 構造化プログラミング手法 ==== これまでは、問題が与えられたとき以下のように仕事を切り分けていました。\\ 1.問題が与えられる\\ 2.必要な変数を考える\\ 3.仕事をまとまった単位に分けて細分化する(サブルーチン化)\\ 4.細分化された仕事ごとに、処理をまとめる\\ 5.処理を関数化する\\ 6.必要な場面で、必要な関数を呼び出し全体の処理の流れを完成させる。\\ \\ == 実際の処理の例 == じゃあ、ってことで、実際に処理をまとめて関数で処理していく例を見てみましょう。 問題は以下のようになっています。 あなたは、とある学校の教務(学生の成績などを処理する係)担当の先生です。 それで、あなたは業務として、N人所属の学級の成績の処理を任されました。 学級の各学生は、それぞれ何科目かの試験を受けていて、成績のデータとして以下の数値が必要です。 各学生について、 * 名前 * 各科目の点数 * 各学生の全科目に対する平均点 学級について * 全体の全科目に対する平均点 * 全学生の科目ごとの平均点(国語の平均点、数学の平均点・・・) \\ さて、どのように処理していきましょうか?\\ \\ === データと処理をピックアップする === \\ 学生数 N人:\\ 科目数 sNum教科:\\ * N人分の名前リスト => stringの配列  * 各科目の点数 => intの配列 * 配列数は 科目数sNum x 学生数 N * 各学生の科目平均点 floatの配列 学生人数分 average[N] 学級について\\ * 全体の全科目に対する平均点 float の変数1つ * 全学生の科目ごとの平均点(国語の平均点、数学の平均点・・・) float の 科目数分(sNum)の配列           ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\\ さらに実際に数値が入った例を考えてみる。\\ **学生数5人の学級で、3科目の試験を行った場合のプログラム**を考えてみる。\\ すなわち\\ * 学生数 N=5 人 * 山田、佐藤、鈴木、後藤、佐々木がクラスのメンバー * 科目数 sNum=3 教科 * 0:国語 1:理科 2:社会 が試験科目 点数は以下のようになったらしいです。\\ |< 30% >| ^ No ^ 氏名 ^ 国語 ^ 理科 ^ 社会 ^ | 01 | 山田 | 80 | 50 | 88 | | 02 | 佐藤 | 75 | 75 | 75 | | 03 | 鈴木 | 80 | 80 | 85 | | 04 | 後藤 | 60 | 60 | 55 | | 05 | 佐々木 | 100 | 65 | 50 |
各学生の点数
=== 変数の割り当て === 実際に処理に使われる変数を割り当てていきます。\\ string name[N] = {"yamada","satou","suzuki","gotou","sasaki"}; //5(=N)人学級のメンバー名 山田、佐藤、鈴木、後藤、佐々木がクラスのメンバー string sname[sNum] = {"国語","理科","社会"}; //3(=sNum)科目の各科目名 次に点数関係\\ //N人の学生分のsNum教科文の得点の配列 int point[N][sNum] = {{80,50,88},//yamadaの得点   {75,75,75},//satouの得点   {80,80,85},//suzukiの得点   {60,60,55},//gotouの得点   {100,65,50}//sasakiの得点   };//sNum 0:国語 1:理科 2:社会 float totalAverage; //全体の全科目の平均点 float student_ave[N]; //各学生ごとの全教科の平均点(sum(各教科点)/3)x学生数分N float subject_ave[sNum]; //各教科ごとの平均点 [[#2次元配列覚えてますか?|2次元配列覚えてる?]] \\ === 関数を作って、割り当てた変数に目的の結果を代入していく === 次は、仕事を関数としてまとめていきます。\\ C言語のプログラマの仕事は主に、変数を渡されたときに、指示された通りに動く関数を設計することです。\\ (関数が難しいとか言ってる人は、プログラマにはなれないよ!)\\ もう一回問題を確認します。\\ あなたは、とある学校の教務(学生の成績などを処理する係)担当の先生です。 それで、あなたは業務として、N人所属の学級の成績の処理を任されました。 学級の各学生は、それぞれ何科目かの試験を受けていて、成績のデータとして以下の数値が必要です。 各学生について、 * 名前 * 各科目の点数 * 各学生の全科目に対する平均点 学級について * 全体の全科目に対する平均点 * 全学生の科目ごとの平均点(国語の平均点、数学の平均点・・・) ここで、求めなければならないものをまとめてみます。\\ データとして以下のものがすでに用意されているとします。\\ **各学生について、** * 名前 * 各科目の点数 その時に、\\ **各学生について、** * 各学生の全科目に対する平均点 **学級について** * 全体の全科目に対する平均点 * 全学生の科目ごとの平均点(国語の平均点、数学の平均点・・・) を求める。\\ というのが、今回の処理になります。\\ これらを求めるために__少なくとも3つの関数__を作らなければならなそうです。\\ - 各学生に対して学生の全科目に対する平均点 を求める関数 - 学級全体に対して、全体の全科目に対する平均点 を求める関数 - 学級全体に対して、科目ごとの平均点 を求める関数 1つずつ考えていきます。\\ == 各学生に対して学生の全科目に対する平均点 を求める関数(設計) == 今回のデータでは、学級内の5名の各学生は、3教科の試験を受けています。\\ 各学生の3科目の平均点を求めることになります。\\ 求めた各学生の平均点は、 float student_ave[N]; //各学生ごとの全教科の平均点(sum(各教科点)/3)x学生数分N\\ に代入します。(そのために用意した変数だもの)\\ __各学生__の全教科の__平均点を求める__関数なので、関数名は、\\ calcStudentAverage //各学生に対し教科の平均点を計算する関数 ぐらいにしましょう。\\ そのほか各学生の教科平均の計算に必要なものは、\\ \\ * 学生の点数データを表す配列 **int point[N][sNum]:**学生の実際の点数のデータが入っている * 学生数 **N**:処理を学生数分繰り返そうと思ったときに学生の数が必要 * 試験の行われた教科数 **sNum**:学生ごとの全科目に対する平均点=学生ごとの全科目の点数の合計/科目数 \\ ぐらいかと思います。\\ まとめると\\ - **calcStudentAverage**は全学生の全点数のデータをスキャンして、 - 学生数**N**人分の教科平均(**(国語+理科+社会)/sNum **)を計算して、 - **float student_ave[N]**に代入する関数である。 と言えます。\\ \\ なので、最終的に関数の設計としては以下のようになります。\\ //戻り値 無し //第1引数 学生の点数のデータを表す配列(の先頭アドレス) //第2引数 学生数 //第3引数 教科数 //第4引数 平均点の入れ物 //プロトタイプ宣言: void calcStudentAverage(int _p[N][sNum], int _n, int _snum, float _ave[N]); == 各学生に対して学生の全科目に対する平均点 を求める関数(実装) == さっき設計した、calcStudentAverageを実装していきます。 //戻り値 無し //第1引数 学生の点数のデータを表す配列(の先頭アドレス) //第2引数 学生数 //第3引数 教科数 //第4引数 平均点の入れ物 //プロトタイプ宣言: void calcStudentAverage(int _p[N][sNum], int _n, int _snum, float _ave[N]); やることは、\\ - 平均点の初期化 - 全科目の平均の計算(人数分) です。\\ 引数の役割はそれぞれ、\\ * int _p[N][sNum] => 得点{国語、理科、社会}x人数分のデータ N x sNum = 5 x 3 の配列 * int _n => 学生の人数 * int _snum => テストのあった科目数 * float _ave[N] => 各学生の平均点を格納する変数 \\ したがって、\\ ---- **平均点の初期化**\\ for(int i=0;i **平均点の計算**\\ for(int i=0;i ---- 全部まとめると。 void calcStudentAverage(int _p[N][sNum], int _n, int _snum, float _ave[N]) { for(int i=0; i == 学級全体に対して、全体の全科目に対する平均点を求める関数(設計) == 同様に、学級の人数分の全科目の平均を求める関数を作っていきます。\\ void calcSubjectAverage(int _p[N][sNum],int _n, int _snum,float _ave[sNum]); //第1引数 学生の名前を表す配列 //第2引数 学生の平均点データを表す配列 //第3引数 学生の数 == 学級全体に対して、全体の全科目に対する平均点を求める関数(実装) == == 学級全体に対して、全体の全科目に対する平均点を求める関数(設計) == == 学級全体に対して、全体の全科目に対する平均点を求める関数(実装) == あいあいあ\\ still under construction... === 2次元配列覚えてますか? === == 2次元配列の宣言 == 基本的には1次元配列と同じですが、行と列の要素数を書かなければならない\\ (宣言文) 型名 配列名[行の要素数][列の要素数]; (例) // 3行x4列のint型の2次元配列 int a[3][4]; == 2次元配列の初期化 ==  1次元配列と同様,初期化子を{}で囲み,先頭から順にカンマで区切る。\\ //宣言文 型名 配列名[行要素数][列要素数] = { 値1, 値2, 値3, ...   }; 1.初期化 基本的な書き方\\  初期化リストを次元に対応させて{}で区切ります。\\ (例1) int a[2][3] = { {1,2,3}, {4,5,6} }; (例2) int a[2][3] = { {1,2,3}, // 行と列の対応と明確に... {4,5,6} }; 2.要素数が足りない場合\\  初期化子の足りない要素は0で初期化されます。ただし{}の囲み方によって初期化の仕方が異なるので注意が必要です。\\ (例) int a[2][3] = {1,2} // {1,2,0,0,0,0}になる int a[2][3] = {{1},{4,5}} // {{1,0,0},{4,5,0}}になる \\ ==== 今回のやつ ==== N人の学生、sNum教科分の得点が必要です。\\ N=5、sNum=3の時なら 5x3=5行x3列の配列が必要になりそうです。\\ 宣言と同時に初期化するパターンで書くと、以下のようになりそう。\\ //N人の学生分のsNum教科分の得点の配列 int point[N][sNum] = {{80,50,88},//yamadaの得点   {75,75,75},//satouの得点   {80,80,85},//suzukiの得点   {60,60,55},//gotouの得点   {100,65,50}//sasakiの得点   }; //sNum 0:国語 1:理科 2:社会 under construction