C++でのさまざまな演算子のオーバーロードについて詳しく説明する

1.等しい演算子のオーバーロード

注意が必要なのは、等号演算子をオーバーロードしない場合、システムはデフォルトで等号演算子のオーバーロードを浅い代入の形式で生成することです。いわゆる浅い代入は、メンバーのプロパティを直接割り当てることです。ターゲットオブジェクトの現在のオブジェクトへの変換(ディープコピーを参照)およびシャローコピー。詳細については、私の記事「C++-コピーコンストラクターの説明」で説明しています。

Object 
{
    
    
public:
//其他的构造函数、析构函数不是本篇文章重点,省略。
    void operator=(const Object& obj)
    {
    
    
         this->value=obj.value;
    }
    /*
    在主函数中使用obja=objb=objc,等价于下面的方法调用:
    obja=objb.operator=(objc);
    obja=operator=(&objb,objc);
    */
private:
    int value;
}

上記の代入文については、次の3点を説明する必要があります
。①この代入文は、代入の過程で値が変化するため、constで変更
できません②このメソッドは、戻り値が無効であるため、連続代入を実装できません。 voidをObjectに変更すると、連続代入が可能になります
。③オブジェクトはmain関数内にあるため、参照により現在のメソッドに入り、objオブジェクトはこのオーバーロードされた関数の呼び出し期間の影響を受けません。参照により返送できるように

等号演算子をオーバーロードする場合は、次の2つの場合があり
ます。①自分で設計した型とオブジェクトはなく、どちらも基本型である場合、システムは2つのオブジェクトのメンバー属性アドレスをキャプチャし、のデータを直接インポートします。ターゲットオブジェクトのメンバー属性を現在のオブジェクトメンバープロパティに追加します。
②メンバープロパティに基本タイプ以上のものがある場合、等号演算子をオーバーロードしないと、システムはデフォルトの浅い代入ステートメントを生成します。

2、および演算子のオーバーロード

class Int
{
    
    
private:
   int value;
public:
    //前置加加
   Int& operator++()
   {
    
    
       this->value+=1;
       return *this;
   }
    //后置加加
   Int operator++(int)
   {
    
    
       Int tmp = *this;
       ++* this;//调用前置加加
       return tmp;
   }
    //对象+对象
   Int operator+(Int& b)const
   {
    
    
       Int c;
       c.value   = this->value + b.value;
       return c;
   }
    //对象+数值
   Int operator+(int val)const
   {
    
    
       Int c;
       c.value = this->value + val;
       return c;
   }
   
};
//数值+对象
Int operator+(const int val, const Int& a)
{
    
    
    return a + val;//调用Int operator+(int val)const 这个方法
}

3.アドレス演算子のオーバーロード

class Int
{
    
    
private:
   int value;
public:
   //省略构造函数、等号运算符重载,这里主要说明取地址运算符重载
   Int* operator&()
   {
    
    
        return this;
   }
   const Int* operator&()const//加了const的取地址运算符重载是一个常方法
   {
    
    
        return this;
   }
}
int main()
{
    
    
    Int a(10);
    Int b=10;//这句话会先调用构造函数构造一个value成员属性为10的对象,然后把这个对象赋值给b
    const Int c=10;
    const Int *ip=&c;//因为C是常对象,所以就会调用上面的常方法
}

4、++前、++後の演算子のオーバーロード

4.1ポスト++参照の問題:

次のコードからわかるように、ポスト++であるため、元の値を保存するオブジェクトを作成してから、現在の値を1ずつ追加する必要があります。ただし、作成されたオブジェクトの存続期間とオーバーライドの方法post ++メソッドlifetimeと同様に、関数呼び出しが終了すると、スペースが解放されます。したがって、参照を返すことはできません。

 //后置加加
   Int operator++(int)
   {
    
    
       Int tmp = *this;
       ++* this;//调用前置加加
       return tmp;
   }

しかし、参照を返す必要がある場合、静的を追加できますか?次のように:

Int& operator++(int)
{
    
    
    static Int old=*this;
    ++* this;
    return old;
}

上記のコードは静的として定義されているため、post ++を1回実行しても問題はありませんが、静的であるため、static Int old = * thisのみを実行します。一度、post ++を再度実行すると、値は、または前の値を変更しない場合は、次のように変更します。

Int& operator++(int)
{
    
    
    static Int old=*this;
    old=*this;
    ++* this;
    return old;
}

old = * thisという文を追加した後、post-addメソッドを実行するたびに、静的変数oldが現在のオブジェクトに再割り当てされるため、前述の「post-add++が再度実行されたときに値は変わりません。以前と同じ値です。」
変更されたコードを説明する例:
ここに画像の説明を挿入
old = * this;は古いものを更新するため、最後のd出力は12です。

4.2関連する問題の分析

次の演算子のオーバーロードと組み合わせて、Int a = 0; a = a+++1;のコードを分析します。

ここに画像の説明を挿入
ここに画像の説明を挿入

5、オーバーロード型キャスト演算子

(1)暗黙の型変換:
いわゆる暗黙の型変換は、次の例で説明されます。a
= b、この文は実際には最初に整数bの値で作成され、作成されたオブジェクトをaに割り当てます。呼び出しが終了し、このオブジェクトが破棄され、aが破棄されます。
(暗黙の変換を許可しないキーワード:明示的)

暗黙的な型変換が可能なコンストラクターは単一のパラメーターでなければならないことを強調しておく必要があります
ここに画像の説明を挿入

(2)強制型変換:
オブジェクトは強制的に組み込み型になります

//把对象强转成整型
operator int() const
{
    
    
    return value;
} 

強制によって返される型は強制後の型であるため、オーバーロードされた関数は戻り型を設定する必要はありません
。たとえば、次のようになります。flotが返されると、戻り型と競合します。
ここに画像の説明を挿入

6.括弧演算子のオーバーロード

class Add
{
    
    
      mutable int value;//加了mutable这个关键字之后,可以让value这个变量在常方法中也能改变
 public:
       Add(int x=0):value(x){
    
    };
       int operator()(int a,int b)const//括号运算符重载
       {
    
     
            value=a+b;
            return value;
       } 
}
int main()
{
    
    
    int a=10,b=20,c=0;
    Add add;
    c=add(a,b);//调用括号运算符重载,我们也称之为仿函数
    //c=add.operator()(a,b);
    return 0;
}

7.出力演算子のオーバーロード

次の出力演算子のオーバーロードは間違っています。outパラメータは、参照によって呼び出す必要があります。システムコードはプライベート出力ストリームを設定するため、参照呼び出しである必要があります。参照呼び出しでない場合は、コピー構造が呼び出され、コピー構造はプライベートに設定されます。呼び出すことはできません。

class String
{
    
    
private:
      char * str;
public:
      //ostream& operator<<(const String* const this,ostream& out)
      ostream& operator<<(ostream out)const
      {
    
    
           if(str!=NULL)
           {
    
    
                out<<str;
           }
           return out;
      }
      //s1<cout
      //s1.operator<<(cout)
      //operator(&s1,cout)
}

正しいものは次のとおりです
。strの内容をコロケーションに書き込んで返し
ここに画像の説明を挿入
ます。ただし、上記の出力演算子のオーバーロードは次のとおりです。s1 << cout、論理出力演算子のオーバーロードに準拠していません。
したがって、
ostream&operatorを呼び出します。 <<(ostream&out、const String&s)
次に、オブジェクト内で出力演算子のオーバーロードを呼び出します

class String
{
    
    
private:
      char * str;
public:
      //ostream& operator<<(const String* const this,ostream& out)
      ostream& operator<<(ostream& out)const
      {
    
    
           if(str!=NULL)
           {
    
    
                out<<str;
           }
           return out;
      }
      //s1<cout
      //s1.operator<<(cout)
      //operator(&s1,cout)
}
ostream& operator<<(ostream& out,const String& s)
{
    
    
    s<<out;
    //s.operator<<(out);
    //operator<<(&s,out);
    return out;
} 
int main()
{
    
    
     String s1("hello world");
     cout<<s1<<endl<<;
     return 0;
}

8.アスタリスク演算子のオーバーロード

class Int
{
    
    
private:
     int value;
};
class Object
{
    
    
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){
    
    }
    ~Object()
    {
    
    
         if(ip!=NULL)
         {
    
    
              delete ip;
         }
         ip=NULL;
    }
    //✳运算符重载返回这个对象所指向的地址
    Int* operator*()
    {
    
    
        return ip;
    }
    const Int* operator*()const
    {
    
    
        return ip;
    }
    //✳运算符重载返回ip所指向的对象
    Int& operator*()
    {
    
    
        return *ip;
    }
    const Int& operator*()const
    {
    
    
        return *ip;
    }
};
int main()
{
    
    
     Object obj(new Int(10));
     (*obj)->value();
}

9.ポインター演算子のオーバーロード

class Int
{
    
    
private:
     int value;
};
class Object
{
    
    
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){
    
    }
    ~Object()
    {
    
    
         if(ip!=NULL)
         {
    
    
              delete ip;
         }
         ip=NULL;
    }
    //返回所指向的这个对象的地址
    const Int* operator->()const
    {
    
    
        return ip;
    }
}
int main()
{
    
    
     Object obj(new Int(10));
     obj->value();
}

注:「オブジェクトの自由な使用」の問題は、アスタリスク演算子のオーバーロードとポインティング演算子のオーバーロードを組み合わせて使用​​することで実現されます。問題は次のことをもたらします

class Int
{
    
    
private:
     int value;
};
class Object
{
    
    
    Int* ip;//Int是一个类
public:
    Object(Int* s=NULL):ip(s){
    
    }
    ~Object()
    {
    
    
         if(ip!=NULL)
         {
    
    
              delete ip;
         }
         ip=NULL;
    }
    Int& operator*()//重载*,返回ip所指对象本身
    {
    
    
         return *ip;
    }
    const Int& operator*()const
    {
    
    
         return *ip;
    }
    Int* operator->()
    {
    
    
         return &**this;
    }
    const Int* operator->()const
    {
    
    
         return &**this;
         //return ip
    }
}

上記の&**これはどういう意味ですか?

上記のコードでは、次の図と組み合わせて右から左に分析します。これはobjオブジェクトを参照し、*これはobjオブジェクトを示し、**これは✳演算子のオーバーロードを呼び出し、によって示されるオブジェクトを示します。 ip自体、つまりこのTogetherは、ipが指すオブジェクトのアドレスを表します。
ここに画像の説明を挿入
したがって、✳演算子と->演算子を入力した後、Intオブジェクトも取得でき、Obj形式を使用して自由化を実現します。つまり、デストラクタでは、この時点で、ipが指すヒープのスペースは自動的に破棄されるため、手動で解放する必要はありません。

おすすめ

転載: blog.csdn.net/m0_54355780/article/details/122638113