クラス Class (3) メンバ関数と演算子のオーバロード 上級プログラミング講義資料 成蹊大学理工学部情報科学科 1 多重定義 ( オーバロード ) 関数のオーバロード C++ の関数では シグニチャ ( 関数名, 引数の型および個数のこと ) が異なることによって 同名の関数が複数存在することが出来る 演算子のオーバロード四則演算子をはじめとする演算子を 新たに定義したクラスを取り扱うように多重定義することが出来る 2
演算子のオーバロード使用以前 例 : 複素数クラス Complex を定義できたとすると その使い方は int main() { Complex x,y,z; x.input(); // 複素数 xの入力 y.input(); // 複素数 yの入力 z= x.add(y); // xにyを加えた複素数をzに代入 z.print(); // zを表示 cout << endl; 加算のわりには不自然な記法 z = x+y; と書けないか? 3 クラス Complex の定義の例 class Complex { double real, imaginary; // 実数部 real と虚数部 imaginary public: Complex(double a=0, double b=0){ real=a; imaginary=b; void input(){ cout << " 実数部と虚数部を入力せよ -->"; cin >> real >> imaginary; void print(){ cout << real; ; if(imaginary>0) cout << "+"; cout << imaginary << i ; // a+biまたはa-biの形式で表示 Complex add(complex k){ return Complex(real+k.real, imaginary+k.imaginary); 4
演算子のオーバロード 演算子は関数の特殊ケース 例 : + 演算子 operator+ という名の関数 二項演算子における2つの解釈 obj1 + obj2 obj1: 第 1 オペランド obj2: 第 2 オペランド 解釈 1 operator+ を obj1 のクラスのメンバ関数と解釈 obj1.operator+(obj2) と等価 解釈 2 両オペランドとも operator+ の引数と解釈 operator+(obj1, obj2) と等価 この場合 operator+ はメンバ関数とはならない 5 演算子のオーバロード使用後 class Complex { double real, imaginary; // 実数部 real と虚数部 imaginary public: Complex(double a=0, double b=0){ real=a; imaginary=b; void input(){ cout << " 実数部と虚数部を入力せよ -->"; cin >> real >> imaginary; void print(){ cout << real; ; if(imaginary>0) cout << "+"; cout << imaginary << i ; // a+biまたはa-biの形式で表示 Complex operator+(complex k){ return Complex(real+k.real, imaginary+k.imaginary); 6
演算子のオーバロード使用以後 例 : 複素数クラス Complex を定義できたとすると その使い方は int main() { Complex x,y,z; x.input(); // 複素数 xの入力 y.input(); // 複素数 yの入力 z= x+y; // xにyを加えた複素数をzに代入 z.print(); // z を表示 cout << endl; z = x.operator+(y); と書いても良いが そんな書き方をする人はいない 7 演算子をオーバロードする場合の注意 オーバロード可能な演算子 (,),[,],->,*,&,++,--,-,~,!,/,%,+,<<,>>, <,>,<=,>=,==,!=,^,,&&,,=,+=,*=,/=,-=,%= など オーバロード不可能な演算子. ::.*?: sizeof 代入演算子 = について = は 同じクラスのオブジェクト同士であれば代入できるようにオーバロードされている演算子なので 代入 目的以外で使わない限り ユーザがオーバロードする必要はない 優先順位オーバロードされた演算子でも その演算子の元の優先順位や結合規則 ( 左結合性 右結合性 結合性なし ) は変えることがで きない 8
演算子の関数形の例 配列演算子 [] の例 rtype operator[](dtype darg); rtype: リターン型 dtype: 仮引数の型 インクリメント演算子 デクリメント演算子前置の ++ の場合 rtype operator++(); // そのクラスのメンバ関数の場合 rtype operator++(aclass&); //Aclass のメンバ関数でない場合の例 後置の ++ の場合 rtype operator++(int); // そのクラスのメンバ関数の場合 rtype operator++(aclass&,int); //Aclass のメンバ関数でない場合の例 9 他の演算子のオーバロードは? 複素数クラス int main() { Complex x,y,z; x.input(); y.input(); z= x.add(y); z.print(); cout << endl; 演算子を用いた 自然な記述 int main() { Complex x,y,z; cin >> x >> y; z= x+y; cout << z << endl; x+y 以外も上記のようにできるのだろうか? 10
入力演算子 >> 演算子の関数表現 cin >> x >> y; operator>>(cin, x) この関数のプロトタイプはどうなるか? istream& operator>>( istream&, Complex& ); cinを受け取り cinを返す cin( 標準入力 ) は実行環境に1つなので 参照変数で受け渡す 複素数クラスComplexのメンバ関数ではない! 11 出力演算子 << 演算子の関数表現 (2) cout << z << endl; operator<<(cout, z) この関数のプロトタイプはどうなるか? ostream& operator<<( ostream&, Complex ); coutを受け取り coutを返す cout( 標準出力 ) は実行環境に1つなので 参照変数で受け渡す 複素数クラスComplexのメンバ関数ではない! 12
cin, cout の参照渡しについて main ostream クラスのオブジェクト cout<<y; cin>>x; istream クラスのオブジェクト 13 cin, cout の参照渡しについて main 関数 operator>> cout<<y; cin>>x; operator>>(istream inst,? cin のコピーを受け取っても意味はない 14
cin, cout の参照渡しについて main 関数 operator>> inst cout<<y; cin>>x; istream& operator>>(istream &inst, ){ ; return inst; operator>> 関数は cin 自体を inst という名前で使用する そして最後に使用した inst つまり cin を返す 15