参照型とは、変数・定数の別名を意味します。変数・定数の別名なので、宣言と同時に
初期化をする必要があります。普通の代入と異なり、キャストして代入することはできません。
参照の宣言は型の後に「&」をつけます。
int i, j ;
char c ;
int& r1 = i ; // r1 は 整数オブジェクト i の別名となる
int& r2 ; // エラー:参照型変数は初期化時に
// 参照対象を明示しなければならない
int& r3 = c ; // エラー:型違反(キャストは許されない)
r1 = 10 ; // i にも10が代入される
|
上の例で、iとr1は同じメモリー領域を共有するため、r1に10を代入するという動作は
iにも10が代入されるという意味になります。
参照が使われるのは、関数の引数、戻り値で、それ以外の用途は余りありません。
では、関数の引数に参照型と参照を使わない場合の比較をしてみます。
参照 |
非参照 |
void func(int& n){
n++;
}
void main(){
int i = 10;
func(i);
cout << i << endl;
} |
void func(int n){
n++;
}
void main(){
int i = 10;
func(i);
cout << i << endl;
} |
11 |
10 |
参照型の場合、func関数内の変数nはmain関数内の変数iの別名になります。
つまりこの2つの変数は同じ物になります。したがって、func関数内で、変数nの
値を変更すると、main関数内の変数iも変更されることになります。
非参照型の場合、mainからfuncを呼ぶ際に、変数iが一時的にコピーされ、
func関数内の変数nに渡されます。func関数内で、nの値を変更しても、それは
iのコピーであるために、変数iには影響しません。
参照型は戻り値にも指定できます。
参照 |
非参照 |
int& func(){
static int i = 10;
return i;
}
void main(){
cout << func()++ << endl;
cout << func()++ << endl;
} |
int func(){
static int i = 10;
return i;
}
void main(){
cout << func()++ << endl; //コンパイルエラー
cout << func()++ << endl; //コンパイルエラー
} |
10 11 | |
戻り値が参照型と言うことは、func関数の戻り値と、func関数内の静的変数iが同じ物である
ということです。つまり、この戻り値を「++」などで変更すれば、func関数内の静的変数iが
変更されると言うことになります。
参照型のメリットは2つあります。
参照型のメリット
- 関数呼び出しで無用なコピーを防ぐ
- 関数呼び出しの連打ができる
|
関数呼び出しの連打とは、以下のようなことを言います。
void main(){
cout << "abc" << 'c' << endl;
} |
後述しますが、C++の演算子は一種の関数として定義され、自分で作ることができます。
つまり、ostreamクラスの「<<」演算子は戻り値として自分自身を返します。つまり
「cout」が返ってくるために、その戻り値に対して「<< 'c'」を呼ぶことができます。
さらにその戻り値が「cout」なので、「<< endl」を行うことができるのです。
もし、関数の引数にメンバー変数が多く定義されている構造体を渡したい場合、
構造体のメンバー変数全てがコピーされて、関数に渡されます。戻り値も同じで、
全てのメンバー変数がコピーされて呼び出し元に戻ります。もし構造体のメンバーが
1Mbytesもあれば、1MBytes分コピーされてしまいます。これは非常に効率が悪い操作に
なります。これを解決するのが参照型というわけです。
なお、参照型の例は次章で示します。