- ベストアンサー
C++のテンプレートクラスにおける参照と演算子の組み合わせについて
- C++のテンプレートクラスで参照と演算子を組み合わせると、配列を2次元的に利用することができます。
- T&という記述があることで、演算子()の動作が再定義されているため、mArrayを2次元配列のように扱えます。
- 参照は必ず初期化が必要とされますが、この場合、演算子()の引数で初期化されています。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
質問は、template とは直接関係なく、 「operator() とは、どういう演算子定義なのか」「参照を返す関数は何の役にたつのか」の2点ですね。 まず「参照を返す関数は何の役にたつのか」について。 参照を返す関数の簡単な例です。 ---ここから--- #include <stdio.h> #include <iostream> class classA { int value_[2]; public: classA() {value_[0] = 0; value_[1] =1;} int& value(int index) {return value_[index];} void output(void) { std::cout << "value[0]=" << value_[0] << ", value[1] = " << value_[1] << std::endl;} }; int main(int argc, char *argv[]) { classA data; int& v = data.value(0); v = 2; data.output(); } ---ここまで--- このmain関数内での value 関数呼び出しは、メンバ変数「value_[0]」への参照を返します。 main関数で宣言した変数vは、dataのメンバvalue_[0]への参照になっていますので、 変数vへの代入はそのまま、dataのメンバvalue_[0]への代入になります。 (そのため、上述のプログラムを実行すると「value[0]=2, value[1]=1」と表示されます。 このように、参照を返す関数によって、呼び出し元からメンバ変数を直接書き変えたりできるようになるのです。value関数への引数を1にすれば、vへの代入で value_[1]が書き変えられるようになります。 さらに、単に代入するだけなら、一旦変数に代入する必要はなく、 --- int& v = data.value(0); v = 2; --- この2行はまとめて --- data.value(0) = 2; --- と書けます。参照を返す関数にすることで、「関数呼び出し」部分がそのまま、まるで変数であるかのように代入可能になるのです。 次にoperator() について。 operator()は、クラスインスタンスを、まるで関数であるかのように使える機能です。 ここで、さらにclassA に --- int& operator()(int index) {return value_[index];} --- というメンバ関数valueと同じ内容な「operator()」の定義を追加すれば、 変数dataに対する演算子「operator()」の呼び出しである「data(x)」は、「data.value(x)」と同じ意味になります。 つまり、 --- int& v = data(0); v = 2; --- とか --- data(0) = 2; --- といった記述ができるようになるのです。 data(0)は、メンバ変数 value_[0] への参照を返しますから、 これで、value_[0] への代入ができるわけです。
その他の回答 (1)
- haniriito
- ベストアンサー率57% (12/21)
>それと、参照というのは、利用するときには必ず初期化が必要、と学習したのですが、 >この場合、初期化の処理になっているのでしょうか。 一言に「参照」とひとからげに理解しているから混乱しているのだと思います。 例示されたような int& m = n; というのは、「参照型の変数mを宣言しようとしている」ということはご理解されていますよね? ”m”は何か別の「実体」を指し示す参照なので、単に int& m; と書いただけでは何を参照しているのかまったく不明なので、初期化(=実体を教える)が必要になるというわけです。 一方、 T& operator()( int index0, int index1 ) { return mArray[ index1 * mSize0 + index0 ]; } というのは、既に存在する(←コレ重要!)mArray[]という配列のどれか一つを「参照」として返す、という意味であって、前述の「参照型の変数を宣言する」というのとは意味が違います。 その本には、このArray2Dテンプレートクラスの用法例として Array2D<int> array2d_int; array2d_int.setSize(100,20); array2d_int(5,3) = 1234; // <-- ここで上のoperator()関数が使われる みたいなのが出てませんか? もうおわかりと思いますが、 array2d_int(5,3)と書くことで2次元配列のうちの(5,3)の部分だけが参照として返されるので、=で代入したり、読み出したりできるということになります。 蛇足ですが、関数の引数として参照を使用できます。 void swap_int(int& lhs, in& rhs) { int tmp = lhs; lhs = rhs; rhs = tmp; } とswap_intという関数を用意して、main関数などから int a = 5; int b = 3; swap_int(a, b); を実行すれば、a=3、b=5となって帰ってきます。
お礼
回答ありがとうございました。
補足
haniriitoさん、迅速な回答本当にありがとうございます! 今まで学習してきた参照と、今回の参照は違うということでいいんでしょうか? T& operator()( int index0, int index1 ) { return mArray[ index1 * mSize0 + index0 ]; } の部分で、T& となっている理由がわかりません。 T operator()( int index0, int index1 ) {//&の記述が消してある return mArray[ index1 * mSize0 + index0 ]; } 上記のように書いた場合、なにか不具合があるのでしょうか。 また、operatorを参照するという使い方がよくわかりません。 このような場合はreturnで帰ってくる部分が参照先になるのでしょうか。 たび重なる質問すみません。 お願いします。
お礼
回答ありがとうございます! 丁寧な説明で、理解することができました;; おっしゃる通りで、templateはあまり関係ありませんでしたすいません。 template class だったせいで、ちょっと難しそうだなっていう先入観にやられてました。 自分じゃどうにもできなかったので、本当に感謝です! ありがとうございました!!