c++のオペレータリロード(回転)

4140 ワード

一、オペレータリロードとは
オペレータのリロードは、オペレータとリロードの2つの部分に分けられます.リロードといえばよく知られているのではないでしょうか.これはコンパイル時の多態で、リロードは実際に関数リロードとオペレータリロードに分けることができます.演算子のリロードと関数のリロードの違いは、オペレータがリロードするのは必ずオペレータであることです.オペレータの再ロードとは、まず直感的に見てみましょう.
#include <iostream>

using namespace std;

int main()
{
    int a = 2 , b = 3;
    float c = 2.1f , d = 1.2f;
    cout<<"a + b = "<<a+b<<endl;
    cout<<"c + d = "<<c+d<<endl;
    return 0;
}

オペレータ「+」がfloatとintの2種類の加算計算を完了するのを見ました.これがオペレータの再ロードです.これらの内蔵型のオペレータのリロードはすでに実現されていますが、今私たちが自分で書いたクラスでも類似の加算を実現するにはどうすればいいのでしょうか.たとえば現在、2つの点の加算を実現するには、横長座標を加算する点クラスpointがあります.この場合、オペレータのリロード関数を自分で書く必要があります.
#include <iostream>

using namespace std;

class point
{    
    double x;
    double y;
public:
    double get_x()
    {
        return x;
    }
    double get_y()
    {
        return y;
    }
    point(double X = 0.0 , double Y = 0.0):x(X),y(Y){};
    point operator +(point p);
};
//     “+”
point point::operator +(point p)
{
    double x = this->x + p.x;
    double y = this->y + p.y;
    point tmp_p(x,y);
    return tmp_p;
}
int main()
{
    point p1(1.2,3.1);
    point p2(1.1,3.2);
    point p3 = p1+p2;
    cout<<p3.get_x()<<" "<<p3.get_y()<<endl;
    return 0;
}

二、オペレータの再ロードを実現する二つの方法
オペレータのリロードの実装方法は、「友元関数」または「クラスメンバー関数」の2つです.
1.ユーティリティー関数リロードオペレータのフォーマット:
class   
{
    friend      operator    (   );
};
//      :
     operator   (   )
{
    //   
}

2.クラスメンバー関数はオペレータの再ロードのフォーマットを実現する:
class   
{
public:
         operator    (   );
};
//      
       ::operator    (   )
{
    //   
}

そう言えば、この2つの実装方式の違いを比較するのに十分ではありません.ポイントクラスの「+」と「-」のリロードをそれぞれ2つの実装方式で書きます.コードは以下の通りです.
#include <iostream>

using std::endl;
using std::cout;

class point
{    
    double x;
    double y;
public:
    double get_x()
    {
        return x;
    }
    double get_y()
    {
        return y;
    }
    point(double X = 0.0 , double Y = 0.0):x(X),y(Y){};
    friend point operator -(point p1,point p2);
    point operator +(point p);
};
//     “-”
point operator -(point p1,point p2)
{
    double x = p1.get_x() - p2.get_x();
    double y = p1.get_y() - p2.get_y();
    point p3(x,y);
    return p3;
}
//     “+”
point point::operator +(point p)
{
    double x = this->x + p.x;
    double y = this->y + p.y;
    point tmp_p(x,y);
    return tmp_p;
}
int main()
{
    point p1(1.2,3.2);
    point p2(1.1,3.1);
    point p3 = p1+p2;
    point p4 = operator-(p1,p2);
    cout<<p3.get_x()<<" "<<p3.get_y()<<endl;
    cout<<p4.get_x()<<" "<<p4.get_y()<<endl;
    return 0;
}

ここは皆さんが見たかどうか分かりませんが、友元関数を使用して二元オペレータを再ロードする場合-「場合、形式パラメータは2つですが、クラスメンバー関数を使用する場合、形式パラメータは1つしかありません.この場合、クラスメンバー関数にthisポインタが存在するため、これは1つのパラメータに相当します.したがって、クラスメンバーがオペレータの再ロードを実現するために必要な形式パラメータは元より1つ少ないです.たとえば、クラスメンバー関数を使用して一元オペレータを実現する」-「パラメータは必要ありません.そのため、演算子のリロードは[],(),->および=ではできません.
実際の開発では、単一演算子はメンバー関数として再ロードすることを推奨し、両目演算子は友元関数として再ロードすることを推奨します.通常、二重演算子をメンバー関数としてリロードするよりも友元関数としてリロードするほうが便利ですが、二重演算子はメンバー関数、たとえば付与演算子=としてリロードする必要がある場合があります.また、オブジェクト内部のステータスを変更する必要がある場合は、一般的にクラスメンバー関数を使用して変更することを選択できます.
三、演算子の再ロードの原則
このように見ると、演算子のリロードは簡単ですが、実際には演算子のリロードもいくつかの原則に従います.
1.C++では既存のC++演算子のみをリロードでき、ユーザー自身で新しい演算子を定義することはできません.
2.C++のほとんどの演算子は、メンバーアクセス演算子を除いてリロードできます.役割ドメイン演算子:、長さ演算子sizeofおよび条件演算子?:.
3.演算子のリロード後に演算子のオペランド(オペランド)の個数を変更することはできません.「+」は2つのオペランドを実装する演算子で、リロード後も両目演算子です.
4.リロードは、演算子の既存の優先度と既存の結合性を変更することはできません.
6.演算子のリロードは、すべてC++で定義された基本データではありません.これは、基本タイプデータに使用される演算子の性質をユーザーが変更しないようにするためです.
 
四、なぜ演算子の再ロードを行うのか
演算子のリロードについては、このような多くの原則に従う必要がありますが、なぜ演算子のリロードを行うのでしょうか.なぜoperator+()の代わりにadd()関数を書かないのですか??個人感覚C++で演算子のリロードをサポートするのは、内蔵データ型と統一した操作のため、例えば、c=a+bとc=add(a,b)のどちらが直感的に見えるかは、明らかに前者です.また、intやdoubleなどの内蔵データ型のように、自分たちで定義したデータ型を操作するのが便利であることを望んでいます.この加算の例を挙げると少し悪いかもしれませんが、現在重荷を加えている演算子は[],<,^,|などは?このとき、私たちはどんなメンバー関数で代用しますか??代わりはどんな効果がありますか?この関数が何をするのか一目でわかりますか??