1. 程式人生 > >操作符重載!

操作符重載!

using tro 操作符函數 ostream pac opened blog bool 過程

操作符重載為操作符提供不同的語義

技術分享
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
int main()
{
    Complex c1 = {1,2};
    Complex c2 = {3,4};
    Complex c3 = c1 + c2;//編譯出錯

    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}
View Code

上個例子中,不能用“+”直接操作兩個結構體,改動一下,提供一個函數。

技術分享
//增加一個add函數
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
Complex add(const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}
int main()
{
    Complex c1 
= {1,2}; Complex c2 = {3,4}; Complex c3 = add(c1,c2);//編譯出錯 cout<<"c3.a = "<<c3.a<<endl; cout<<"c3.b = "<<c3.b<<endl; cout << "Press any key to continue..." << endl; cin.get(); return 0; }
View Code

技術分享

C++中操作符重載的本質

C++中通過operator

關鍵字可以利用函數拓展操作符,operator本質是通過函數重載實現操作符重載。

技術分享
//把add替換為“operator+"
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}

int main()
{
    Complex c1 = {1,2};
    Complex c2 = {3,4};
    Complex c3 = operator+ (c1,c2);
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    c3 = c1 + c2;
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}
View Code

技術分享

operator關鍵字拓展的操作符應用到類。

利用友元friend關鍵字可以例外的開放private聲明的類成員的使用權限

技術分享
//友元friend和全局函數 使操作符重載應用與類
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a=0,int b=0)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    friend Complex operator+ (const Complex& c1,const Complex& c2);
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}

int main()
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;
    cout<<"c3.a = "<<c3.getA()<<endl;
    cout<<"c3.b = "<<c3.getB()<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}
View Code

技術分享

以上是“+”操作符,接下來重載“<<”操作符

技術分享
//左移操作符重載
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a=0,int b=0)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    friend Complex operator+ (const Complex& c1,const Complex& c2);
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<"+"<<c.b<<"i";
    return out;//返回ostream類型的out 是為了能連續輸出
}
int main()
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;
    //cout<<c1; -> operator<<(cout,c1) 如果沒有返回cout的話,不能接著輸出endl
    cout<<c1<<endl;//->((operator<<(cout,c1)))<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}
View Code

技術分享

小結:

1、操作符重載的本質是通過函數擴展操作符的語義 2、operator關鍵字是操作符重載的關鍵

3、friend關鍵字可以函數或類開發訪問權限 4、操作符重載遵循函數重載的規則

通過operator關鍵字能夠講操作符定義為全局函數,操作符重載的本質就是函數重載,那麽類的成員函數是否可以作為操作符重載的函數

技術分享
#include <iostream>
#include <cstdlib>
using namespace std;

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a,int b)
    {
        this ->a = a;
        this ->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    Complex operator+ (const Complex& c2);
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0,0);
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";//數學裏的虛數表示法
    return out;//考慮c++標準庫重載的左移操作符支持鏈式調用,所以要返回cout,如果不返回,則不能接著返回endl了;
}
int main(int argc,char *argv[])
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)

    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
View Code

輸出結果一樣。

用成員函數重載的操作符比全局操作符函數少一個參數,即左操作符,而且不需要friend。

問題來了,什麽時候用全局的函數重載,什麽時候有成員函數重載。

1,當無法修改左操作數的類時,使用全局函數進行重載 2,=,[],(),->操作符只能通過成員函數進行重載。

技術分享
//Array.h
#ifndef ARRAY
#define ARRAY
class Array
{
private:
    int mLength;
    int* mSpace;
public:
    Array(int length);
    Array(const Array& obj);
    int length();
    ~Array();
    int& operator[] (int i);
    Array& operator= (const Array& obj);
    bool operator== (const Array& obj);
    bool operator!= (const Array& obj);
};
#endif // ARRAY
//Array.c
#include "array.h"

Array::Array(int length)
{
    if(length < 0)
    {
        length = 0;
    }
    mLength = length;
    mSpace = new int[mLength];
}
Array::Array(const Array &obj)
{
    mLength = obj.mLength;
    mSpace = new int[mLength];
    for(int i = 0;i<mLength;i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}
int Array::length()
{
    return mLength;
}
Array::~Array()
{
    mLength = -1;
    delete[] mSpace;
}
int& Array::operator[] (int i)//作為左值的調用語句返回的必須是引用
{
    return mSpace[i];
}
Array& Array::operator= (const Array& obj)//返回Array的引用是為了可以連續賦值
{                                //a3 = a2 = a1;->a3 = a2.operator=(a1);
    delete[] mSpace;//先釋放自己的原有的堆空間 因為接下來要申請
    mLength = obj.mLength;
    mSpace = new int[mLength];
    for(int i = 0;i<mLength;i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    return *this;
}
bool Array::operator== (const Array& obj)
{
    bool ret = true;
    if(mLength==obj.mLength)
    {
        for(int i=0;i<mLength;i++)
        {
            if(mSpace[i] != obj.mSpace[i])
            {
                return false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    return ret;
}
bool Array::operator!= (const Array& obj)
{
    return !(*this == obj);
}
//main.c
#include <iostream>
#include <cstdlib>
#include "array.h"
using namespace std;

int main(int argc,char *argv[])
{
    Array a1(10);
    Array a2(0);
    Array a3(1);
    for(int i = 0;i<a1.length();i++)
    {
        a1[i] = i+  1;
    }

   for(int i = 0;i < a1.length();i++)
    {
        cout<<"Element"<<i<<":"<<a1[i]<<endl;
    }

     a2 = a1;//-> a2.operator=(a1);
     //a3 = a2 = a1;//->a3 = a2.operator=(a1);
    for(int i=0;i<a2.length();i++)
    {
         cout<<"Element"<<i<<":"<<a2[i]<<endl;
    }
    if(a1 == a2)
    {
        cout<<"a1 == a2"<<endl;
    }
    if(a3!=a2)
    {
        cout<<"a3 != a2"<<endl;
    }
    cout << "Press the enter key to continue ...";
    cin.get();
    return 0;
}
View Code

為什麽要用到賦值操作符重載?

C++編譯器會為每個類提供默認的賦值操作符,但默認的賦值操作符只是簡單的值復制,一旦有指針類的成員變量則就只復制指針,它們將指向同一片空間,而相應的空間就沒用了,所以類中存在指針成員變量時就需要重載賦值操作符

++操作符的重載

++操作符只有一個操作數,且有前綴和後綴的區分。如何重載++操作符才能區分前置運算和後置運算呢?

技術分享
#include <iostream>
#include <cstdlib>
using namespace std;

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a,int b)
    {
        this ->a = a;
        this ->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    Complex operator+ (const Complex& c2);
    Complex operator ++(int);//占位參數
    Complex& operator ++();
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0,0);
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";//數學裏的虛數表示法
    return out;//考慮c++標準庫重載的左移操作符支持鏈式調用,所以要返回cout,如果不返回,則不能接著返回endl了;
}
Complex Complex:: operator ++(int)
{
    Complex ret = *this;//先將當前對象做一個備份
    /*首先解釋++後綴的原理
     int a=0;
     cout<<a++<<endl;則會打印0 且a=1。
     為了模擬這個過程則要先保存一個當前值的備份
    */
    a++;//然後當前對象進行+1操作
    b++;
    return ret;//將備份返回
}
Complex& Complex:: operator ++()//為什麽要返回引用?
{
    ++a;
    ++b;
    return *this;
}
int main(int argc,char *argv[])
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)

    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
View Code

為什麽不用重載&&和||操作符?

首先在語法上是沒有錯誤的,但最好不要去重載,&&和||的特性是短路。

//短路
int a1 = 0;
int a2 = 1;
if(a1&&(a1+a2))
{
    cout<<"Hello"<<endl;
}
//因為a1=0,則(a1+a2)根本不會執行。這個就是所謂的短路。
//如果重載了&&
class Test
{
    int a;
public:
    Test(int i)
    {
      this->a = i;
    }
    Test operator+ (const Test& obj) 
   {
      Test ret = 0;
       ret.a = this->a+obj.a;
       return ret;
    }
    bool operator&& (const Test& obj)
    {
        return a&&obj.a;
    }
};
Test t1 = 0;
Test t2 =1;
if(t1.operator&&(t1.operator+(t2)))
{
    cout<<"Hello"<<endl;
}
//則會先執行+操作,違反了短路原則。

&&和||是c++中非常特殊的操作符。

&&和||內置實現了短路規則,操作符重載是靠函數重載來實現的,操作數作為函數參數傳遞,c++的函數參數都會被求值,無法實現短路規則。

操作符重載!