応用プログラミング 第 11 回 関数の名前 2017 年 11 月 29 日 ( 水 )
第 12 章 関数の名前
今日の内容 * これまでの関数 必ず main 関数 ( 呼び出し元 ) の前に関数定義をする 宣言した仮引数の数と実引数として渡す値の数は同じ 仮引数の型に合わせた値渡し (1) 関数宣言 : 関数の戻り値の型, 名前, 引数の型のみ先行指定 (2) 多重定義 : 引数が異なる同じ名前の関数の作成 (3) デフォルト引数 : 関数の仮引数にデフォルトで引数を指定 (4) 関数テンプレート : 様々な型に対応できる関数の作成
関数宣言 (P.109) * 最初に関数の戻り値の型 関数名 仮引数の型のみ宣言する これにより, main 関数後に関数定義ができる void print(const int [], int); int main(){ const int asize = 5; int array[asize] = {1, 2, 3, 4, 5; print(array, asize); return 0; void print(const int x[], int size){ for(int i = 0; i < size; i++){ cout << x[i] << ; cout << endl; 先に宣言だけ ( 関数宣言 ) 引数の変数名は要らない ( 書いても無視される ) main 関数の後に作成可能このときは普通の関数の作成と同様に行えば良い ( 関数定義 )
関数宣言 (P.110) * 関数宣言では 戻り値の型, 関数名, 引数の型と個数 が決まる void print(const int [], int); * 上の関数宣言に対し, 以下の関数定義は全てエラー void print(const double x[], int size){ void print(const int x[], int size, int n){ int print(const int x[], int size){ void output(const int x[], int size){ 引数の型が異なる引数の数が異なる返却値型が異なる関数名が異なる
関数名の多重定義 ( オーバーロード )(P.110-112) * 全く同じ機能の関数に, 引数の型の違いだけで別名をつけるのは関数の名前が増え, プログラムが分かりにくくなる void swap(int& x, int& y); void swapd(double& x, double& y); void swapch(char& x, char& y); * 多重定義 : 引数が異なれば, 関数に同じ名前をつけることが可能 同じ機能ならば同じ関数名を付けておく方が可読性が上がる void swap(int& x, int& y); void swap(double& x, double& y); void swap(char& x, char& y);
関数名の多重定義 ( オーバーロード )(P.110-112) * 返却値型のみが違う同名の関数は定義できない void swap(int& x, int& y); int swap(int& x, int& y); * 引数が 1 個でも異なれば返却値型は違っても OK void swap(int& x, int& y); int swap(double& x, int& y); * 引数の個数が違う同名関数も許される void input(int& x); void input(int x[], int size);
関数名の多重定義 ( オーバーロード )(P.110-112) * 引数の型が違うだけの同名関数でも, それぞれの関数定義の中身は異なることに注意する. void swap(int& x, int& y){ int tmp = x; x = y; y = tmp; void swap(double& x, double& y){ double tmp = x; x = y; y = tmp; 名前が同じだからといって, 関数定義が一つで良いわけではない
デフォルト引数 (P.113) *2~4 個の整数値の加算を関数で行いたい 個数に合わして一つずつ作る 煩雑! 一つの関数でどの個数でも対応できないか? デフォルト引数 int sum(int, int, int =0, int =0); int main(){ cout << sum(1, 2, 3, 4) << endl; cout << sum(1, 2, 3) << endl; cout << sum(1, 2) << endl; int sum(int x, int y, int z, int w){ return x+y+z+w; * 実引数が 3 個しかない場合 4 個目の引数を 0 として sum を呼ぶ * 実引数が 2 個しかない場合 3, 4 個目の引数を 0 として sum を呼ぶ sum(1, 2, 3, 4) 10 sum(1, 2, 3) 6 sum(1, 2) 3 関数では 4 つの値の和 x+y+z+w を返す
デフォルト引数 (P.113) * 途中の引数のみにデフォルトの値を設定することはできない int sum(int x, int y=0, int z, int w); * デフォルトの値は必ず後ろから順に設定する int sum(int x, int y=1, int z=2, int w=3); * 全ての引数にデフォルトの値を設定することも可能 int sum(int x=0, int y=0, int z=0, int w=0); * 関数宣言をする場合は, 関数宣言のときに, 関数定義のみの場合は, 関数定義のときにデフォルト引数の宣言を行う.
関数テンプレート (P.114) * 全く同じ処理を行える様々な型に対応した関数を作成したい 多重定義で全ての型の分を用意する 膨大な関数の数 関数テンプレートを用いる void swap(int& x, int& y){ void swap(double& x, double& y){ void swap(char& x, char& y){ void swap(string& x, string& y){ template < class T > void swap(t& x, T& y){
関数テンプレート (P.114) template < class T > // T: テンプレート仮引数 この前置きの後に T を含めて宣言されるのが関数テンプレートと呼ばれる 関数の枠組み < イメージ > * 枠組みの用意 ( 非実体 ) template < class T > T sum(t x, T y, T z){ double 型の実引数を受け取ると *double 用に具現化されたテンプレート関数 ( 実体 ) *int 用に具現化されたテンプレート関数 ( 実体 ) int sum(int x, int y){ int 型の実引数を受け取ると double sum(double x, double y){
関数テンプレート (P.114) void print(int x[], int size){ void print(double x[], int size){ void print(char x[], int size){ int main(){ const int size = 3; int a[size] = {1, 2, 3; double d[size] = {1.0, 2.1, 3.0; char c[size] = { a, b, c ; template < class Type > void print(type x[], int size){ for(int i = 0; i < size; i++){ cout << x[i] << ; cout << endl; print(a, size); print(d, size); print(c, size); return 0; // 実行結果 1 2 3 1.0 2.1 3.0 a b c
関数テンプレートライブラリ (P.115) *<algorithm> ヘッダファイルには便利な関数テンプレートがある 1. template <class T> const T& min(const T& a, const T& b) a と b の小さい方を返す関数 2. template <class T> const T& max(const T& a, const T& b) a と b の大きい方を返す関数 3. template <class T> void swap(t& a, T& b) a と b を入れ替える関数 * これらは関数テンプレートなので, 変数型は気にせず使用可能 各ヘッダファイル内に準備されている関数については以下参照 http://cpprefjp.github.io/reference.html
関数名に関する注意事項 (P.116) * コンパイラが関数呼び出しで対応する関数を見つけるためには 引数の数, 引数の型, 戻り値 を調べる # もし型などが異なったとしても, すぐにエラーにはならず, 以下を試行 格上げ :bool を int に, int を double に, 等のデータ型の格上げ 標準変換 :int と double の相互変換, int と unsigned int の変換等 ユーザによって定義された型変換 ( キャスト ) 引数の個数が不定の関数を調査 ( デフォルト引数などによる ) * これらのせいでエラーになる可能性があるので, 関数呼び出しの際は, 特に引数のデータ型に注意する
関数名に関する注意事項 (P.116) 多重定義, デフォルト引数, 関数テンプレートの利用指針 * 基本的には, 関数には別名をつける 多重定義 関数の処理方法, 引数, 型が違うが処理内容は同じ デフォルト引数 引数の個数のみが異なる場合のみ 関数テンプレート 引数の型のみが異なる場合のみ template 関数の関数宣言 template<class Type> void print(type, Type) template 宣言も同時に行う 関数定義の方でも ( 改めて )template 宣言は行う
練習問題 問題. 5 個の整数と実数を別々に入力すると, その中で一番大きい値を出力する以下のプログラムを完成させよ. #include<iostream> // ここに Max 関数の関数定義 int main(){ const int N = 5; int x[n] = {, i = 0; cout << 整数を入力 : ; while(i < N && cin >> x[i]) i++; Max(x, N); // 実行例整数を入力 : 1 5 7 9 3 一番大きい値 : 9 実数を入力 : 1.2 4.9 5.1 3.8 2.4 一番大きい値 : 5.1 double y[n] = {; cout << 実数を入力 : ; i = 0; while(i < N && cin >> y[i]) i++; Max(y, N); return 0;