C++講座4回です
今回は参照渡しについてです。
今回のソースコード
reference.zip
参照とは変数の別名です
別名なので単独で使うことはできません
別名なので元の変数とアドレスは同じになります
感覚的にはポインタに近いです
変数を参照渡しするにはポインタみたいに
int a = 5; int& b = a; // bはaを参照(aの別名)
とします
注意としては参照は初期化しないと使えません(別名なので単体で使えません)
// ↓初期化してないのでコンパイルエラーとなる例 int& c;
上の例はあまりありがたみがないです
参照渡しの主な用途は関数の引数にポインタ代わりとして使います
ポインタと比べて間接参照演算子( * )を使わなくても、そのまま値にアクセスできます
ポインタ同様、関数の引数に変数を渡すときにデータのコピーが発生しないため、
構造体、クラスなどのデータサイズが大きい変数を参照渡しすると
メモリを占有しないし、処理速度も上がります
今回のサンプルです
ポインタとの違いを比較してください
// main.cpp #include <iostream> // ポインタを使って入れ替える例 void Swap(int* c,int* d){ printf("Swap関数ポインタver\t &c = %p c = %d,&d = %p d = %d\n",c,*c,d,*d); int tmp = *d; *d = *c; *c = tmp; } // 参照渡しを使って入れ替える例 void Swap(int& c,int& d){ printf("Swap関数参照渡しver\t &c = %p c = %d,&d = %p d = %d\n",&c,c,&d,d); int tmp = d; d = c; c = tmp; } int main() { int a = 5; int& b = a; // bはaを参照(aの別名) //int& c; // 参照は初期化しないと使えない(コンパイルエラー) // アドレスの確認 printf("&a = %p, a = %d \n",&a,a); printf("&b = %p, b = %d \n",&b,b); b = 10; // 同じアドレスのデータを書き換えている printf("&a = %p, a = %d \n",&a,a); printf("&b = %p, b = %d \n",&b,b); printf("\n"); //--------------------------------------// int c = 5,d = 8; printf("メイン関数\t\t &c = %p c = %d,&d = %p d = %d\n",&c,c,&d,d); printf("\n"); Swap(&c,&d); printf("メイン関数\t\t &c = %p c = %d,&d = %p d = %d\n",&c,c,&d,d); printf("\n"); Swap(c,d); printf("メイン関数\t\t &c = %p c = %d,&d = %p d = %d\n",&c,c,&d,d); return 0; }
おまけに、参照渡しを使った3次元ベクトルクラスの足し算の例を挙げておきます
参照渡しはインスタンスの読み取り専用引数としてよく使われるのでマスターしておいて損はありません
// main.cpp #include <iostream> // 3次元ベクトル class Vector3 { public: float x,y,z; // ベクトルの足し算 Vector3& Add(const Vector3& vec); }; Vector3& Vector3::Add(const Vector3& vec) { // 自分自身のインスタンスのメンバ変数にアクセスするにはthisポインタを使う this->x += vec.x; this->y += vec.y; this->z += vec.z; return *this; // 自分自身のインスタンスを返す } int main() { // 配列の初期化で構造体、クラスもメンバの初期化ができる // 変数のデータ並び順(ここではx,y,zの順)にデータを初期化 Vector3 vec1 = {1.0f,2.0f,3.0f}; Vector3 vec2 = {3.0f,4.0f,5.0f}; Vector3 vec3; printf("x = %.1f,y = %.1f,z = %.1f \n",vec1.x,vec1.y,vec1.z); vec3 = vec1.Add(vec2); printf("x = %.1f,y = %.1f,z = %.1f \n",vec3.x,vec3.y,vec3.z); return 0; }
thisポインタについて補足しておきます
thisはメンバ関数を呼び出したインスタンスのポインタに相当し、
メンバ関数内から自分のクラス内のメンバ変数やメンバ関数にアロー演算子を使ってアクセスできます
(実際にthis->と打ち込んで確認してみると良いでしょう)
thisは省略可能ですが、ここでの例のように
引数とメンバ変数名が重複した場合、メンバ変数を明示するのに使ったり
自分自身のインスタンスを戻り値に返す場合等に使います
ここではvec1からAddメンバ関数から呼び出されているため
thisはvec1のポインタとなります