15章 参照

http://www.geocities.jp/ky_webid/cpp/language/015.html

参照という物が出てきました。ポインタと非常に似ていますね。

面白いのが、間接参照を行わなくて良いというところです。

ポインタの場合はあくまでアドレスを渡しているだけなので間接参照して実体を引っ張ってこないといけませんでした。

参照の場合は元の変数の別名の変数を定義しているだけなので見ているデータは同じだけど変数名だけ違うという奇妙な状態になっているということです。

そして更に面白いのが、値を参照渡しするときに変数をそのまま渡すだけで良いというところです。

#include <iostream>

// numを参照で受け取る
void num2 (int& num) {
    num *= 2;
}

int main() {
    int num = 100;
    num2(num); // numに何も付いてない
    
    std::cout << num << std::endl;
    return 0;
}
$ main
200

このように、num2に値を渡す際に、何もつけていません。ポインタを渡す場合は「&num」と書かなければいけなかったことを考えるとこれは奇妙な仕様ですよね。

また、逆に言えば変数を渡してるだけなのに、値が勝手に書き換えられてしまう可能性があるということにも気をつけなければなりません。ポインタ渡ししてないから大丈夫だろうと思っていても関数の受け取り側が参照受け取りになっていたら値が書き換えられないという保証はありません。

しかし、でもこの機能は使いようによってはかなり便利で強力な機能だと思います。

ポインタと違ってアドレスではないので変なところを参照したりすることもないですし、間接参照の紛らわしさも無くなるので素晴らしいと思います。

ただ難点なのが、宣言に&をつけると参照で、変数に&を付けたらポインタになる、といったようなとっても分かりにくい仕様が微妙ですね。慣れてくればいいんですが、最初のうちは&の扱いが分かりづらくてキツイと思います。僕も少し頭がパニックです。

参照の注意点

更に注意事項を続けます。上のプログラム例のmain関数で、

int& alias = obj.get();

としている部分を、次のように2行に分けてコンパイルしてみて下さい。

int& alias;
alias = obj.get();

すると、コンパイルは失敗します。エラーメッセージを見ると(もちろんコンパイラの種類によってメッセージは違う)「参照が初期化されずに宣言されている」となります。つまり、参照変数を宣言するときには、必ず初期値が必要だということです。理由は「参照変数は、他の変数の別名」だからです。初期化されていないということは、何の別名なのか分かりません。だからエラーなのです。

なるほど。参照はあくまでも変数の別名の定義なので、宣言と同時に実際の変数を代入してあげないとコンパイルエラーとなるわけなんですね。良く分かります。

また、C++C言語と違っていつでもどこでも変数の定義ができるようになったので使う部分で変数を宣言するという書き方にした方が良さそうですね。