応用プログラミング
第11回
関数の名前
今日の内容
(1) 関数宣言:関数の戻り値の型, 名前, 引数の型のみ先行指定 (2) 多重定義:引数が異なる同じ名前の関数の作成 (3) デフォルト引数:関数の仮引数にデフォルトで引数を指定 (4) 関数テンプレート:様々な型に対応できる関数の作成 *これまでの関数 必ずmain関数(呼び出し元)の前に関数定義をする 宣言した仮引数の数と実引数として渡す値の数は同じ 仮引数の型に合わせた値渡し関数宣言(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);
void swap(int& x, int& y);
int swap(double& x, int& y);
*引数が1個でも異なれば返却値型は違ってもOK
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 >
関数テンプレート(P.114)
template < class T > // T:テンプレート仮引数 この前置きの後にTを含めて宣言されるのが 関数テンプレートと呼ばれる“関数の枠組み” <イメージ> template < class T > T sum(T x, T y, T z){ … } *枠組みの用意(非実体)int sum(int x, int y){ … }
*int用に具現化された
テンプレート関数(実体)
double sum(double x, double y){ … }
*double用に具現化された テンプレート関数(実体) int型の実引数を 受け取ると… double型の実引数 を受け取ると…
関数テンプレート(P.114)
template < class Type >
void print(Type x[], int size){ for(int i = 0; i < size; i++){
cout << x[i] << “ ”; }
cout << endl; }
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’}; print(a, size);
print(d, size); print(c, size); return 0;
} void print(int x[], int size){ … }
void print(double x[], int size){ … } void print(char x[], int size){ … }
// 実行結果 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宣言も同時に行う 関数定義の方でも(改めて)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);
double y[N] = {};
cout << “実数を入力:”; i = 0; while(i < N && cin >> y[i]) i++; Max(y, N); return 0; } // 実行例 整数を入力: 1 5 7 9 3 一番大きい値: 9 実数を入力: 1.2 4.9 5.1 3.8 2.4 一番大きい値: 5.1