オーバーロード演算子の例
次の例では,クラス complex を拡張して complex 型のベクタを作成しています。よく使われる演算子をいくつかオーバーロードすることにより,通常の算術構文において一般的な算術関数が提供されます。
例では下記の項目について説明します。
- デフォルトコンストラクタが定義されている。デフォルトコンストラクタやそのほかのコンストラクタを定義しない場合にのみ,コンパイラがデフォルトコンストラクタを生成する
- コピーコンストラクタが明示的に定義されている。通常,コンストラクタを定義しない場合には,コンパイラによってコンストラクタが生成される。代入演算子をオーバーロードする場合は,コピーコンストラクタを定義しなければならない
- 代入演算子がオーバーロードされる。代入演算子をオーバーロードしない場合は,必要に応じてコンパイラがデフォルトの代入演算子を呼び出す。cvector 型の代入演算子をオーバーロードすることにより,行うべき動作を正確に指定する。派生クラスは,代入演算子を継承できないことに注意
- 添え字演算子が,単一引数を持つメンバー関数(オーバーロード時に必要)として定義される。const の指定によって,呼び出し側が引数を変更しないことが保証される。これはコピーや代入の処理を行うときに役立つ。この演算子で,インデックスの値が範囲内(例外処理の実現に適切な範囲)であるかどうかをチェックしなければならない
- 加算演算子がメンバー関数として定義されている。そのため,cvector 型に対してのみ加算が行える。加算するときは,オペランドのサイズが等しいかどうかを常にチェックしなければならない
- 乗算演算子が friend として宣言されていて オペランドの順序が定義される。オペランドの順序を逆にすると,コンパイル時にエラーになる
- ストリーム挿入演算子が,cvector を適切に表示するためにオーバーロードされる。制限された画面サイズ内に表示しきれない大きなオブジェクトには,別の表示方法が必要となる
ソース例
/* complex クラスを拡張して必要な演算子をオーバーロードする方法 */ complexcomplexcomplex
#include <complex> // iostream を含みます。
using namespace std;
// COMPLEX ベクタ
template <class T>
class cvector {
int size;
complex<T> *data;
public:
cvector() { size = 0; data = NULL; };
cvector(int i = 5) : size(i) { // デフォルトのベクタサイズ
data = new complex<T>[size];
for (int j = 0; j < size; j++)
data[j] = j + (0.1 * j); // 任意の初期化
};
/* このバージョンは main() で呼び出される */
complex<T>& operator [](int i) { return data[i]; };
/* このバージョンは代入演算子で呼び出されてコンストラクタをコピーする */
const complex<T>& operator [](int i) const { return data[i]; };
cvector operator +(cvector& A) { // 加算演算子
cvector result(A.size); // 元の演算子を変更しない
for (int i = 0; i < size; i++)
result[i] = data[i] + A.data[i];
return result;
};
/* 乗算 scalar * vector は入れ替えできないので,要素の順序を
指定しなければならない。このフレンド演算子関数によって
適切な乗算が保証される */
friend cvector operator *(T scalar, cvector& A) {
cvector result(A.size); // 元の演算子を変更しない
for (int i = 0; i < A.size; i++)
result.data[i] = scalar * A.data[i];
return result;
}
/* ストリーム挿入演算子 */
friend ostream& operator <<(ostream& out_data, cvector& C) {
for (int i = 0; i < C.size; i++)
out_data << "[" << i << "]=" << C.data[i] << " ";
cout << endl;
return out_data;
};
cvector( const cvector &C ) { // コピーコンストラクタ
size = C.size;
data = new complex<T>[size];
for (int i = 0; i < size; i++)
data[i] = C[i];
}
cvector& operator =(const cvector &C) { // 代入演算子
if (this == &C) return *this;
delete[] data;
size = C.size;
data = new complex<T>[size];
for (int i = 0; i < size; i++)
data[i] = C[i];
return *this;
};
virtual ~cvector() { delete[] data; }; // デストラクタ
};
int main(void) { /* complex ベクタを使用した処理 */
cvector<float> cvector1(4), cvector2(4), result(4);
// 複素数を作成して complex ベクタに代入する
cvector1[3] = complex<float>(3.3, 102.8);
std::cout << "cvector1 です:" << std::endl;
cout << cvector1;
cvector2[3] = complex<float>(33.3, 81);
std::cout << "cvector2 です:" << std::endl;
cout << cvector2;
result = cvector1 + cvector2;
std::cout << "vector の加算結果:" << std::endl;
cout << result;
result = 10 * cvector2;
std::cout << "10 * cvector2 の結果:" << std::endl;
cout << result;
return 0;
}
出力
cvector1 です:
[0]=(0, 0) [1]=(1.1, 0) [2]=(2.2, 0) [3]=(3.3, 102.8)
cvector2 です:
[0]=(0, 0) [1]=(1.1, 0) [2]=(2.2, 0) [3]=(33.3, 81)
vector の加算結果:
[0]=(0, 0) [1]=(2.2, 0) [2]=(4.4, 0) [3]=(36.6, 183.8)
10 * cvector2 の結果:
[0]=(0, 0) [1]=(11, 0) [2]=(22, 0) [3]=(333, 810)