天天看點

16運算符重載運算符重載

運算符重載

  • 運算符重載
    • 概念
    • 限制
    • 基礎
    • 提高
    • 字元串類的實作
    • 附錄運算符和結合性
本人部落格收集自網上前人資料,隻為做筆記複習,而且好的東西應該和大家分享才是!如有冒犯,告知鄙人定會删除

1.概念

  • 什麼是運算符重載
16運算符重載運算符重載

所謂重載,就是重新賦予新的含義。函數重載就是對一個已有的函數賦予新的含義,使之實作新功能,是以,一個函數名就可以用來代表不同功能的函數,也就是”一名多用”。

運算符也可以重載。實際上,我們已經在不知不覺之中使用了運算符重載。例如,大 家都已習慣于用加法運算符”+”對整數、單精度數和雙精度數進行加法運算,如5+8, 5.8 +3.67等,其實計算機對整數、單精度數和雙精度數的加法操作過程是很不相同的, 但由于C++已經對運算符”+”進行了重載,是以就能适用于int, float, doUble類型的運算。

又如”<<“是C++的位運算中的位移運算符(左移),但在輸出操作中又是與流對 象cout 配合使用的流插入運算符,”>>“也是位移運算符(右移),但在輸入操作中又是與流對象 cin 配合使用的流提取運算符。這就是運算符重載(operator overloading)。C++系統對”<<“和”>>“進行了重載,使用者在不同的場合下使用它們時,作用是不同 的。對”<<“和”>>“的重載處理是放在頭檔案stream中的。是以,如果要在程式中用”<< “和”>>”作流插入運算符和流提取運算符,必須在本檔案子產品中包含頭檔案stream(當然還應當包括”using namespace std“)。

現在要讨論的問題是:使用者能否根據自己的需要對C++已提供的運算符進行重載,賦予它們新的含義,使之一名多用。?

  • 運算符重載入門技術推演
    • 為什麼會用運算符重載機制

      用複數類舉例

      Complex c3 = c1 + c2;

      原因 Complex是使用者自定義類型,編譯器根本不知道如何進行加減.是以編譯器給提供了一種機制,讓使用者自己去完成,自定義類型的加減操作。這個機制就是運算符重載機制
    • 運算符重載的本質是一個函數
#include <iostream>
using namespace std;

class Complex
{
public:
    int a;
    int b;
public:
    Complex(int a=, int b=)
    {
        this->a = a;
        this->b = b;
    }
    void printCom()
    {
        cout<<a<<" + " << b << "i" <<endl;
    }
};

//1 定義了全局函數
Complex myAdd(Complex &c1, Complex &c2)
{
    Complex tmp(c1.a + c2.a, c1.b+ c2.b);
    return tmp; //
}

//2 函數名 更新
Complex operator+(Complex &c1, Complex &c2)
{
    cout<<"12345上山 打老虎"<<endl;
    Complex tmp(c1.a + c2.a, c1.b+ c2.b);
    return tmp; //
}



int main()
{

    int a = , b = ;
    int c;
    c = a + b; //1 基礎資料類型 編譯器已經知道了. 如何運算

    // a + bi 複數運算規則
    Complex c1(, ), c2(, );
    Complex c3; //2 類 也是一種資料類型  使用者自定義資料類型 C++編譯器 是不知道如何進行運算
    //c3 = c1 + c2 ;
    //c1--; --c1

    //3 c++編譯器應該給我們程式員提供一種機制 ...
    //讓自定義資料類型 有機會 進行 運算符操作 ====> 運算符重載機制

    //4 運算符重載機制

    //步驟1 普通函數
    //Complex c4 = myAdd(c1, c2);
    //c4.printCom();

    //步驟2 operator+ 函數名稱 //Complex c4  = c1 + c2
    //Complex c4 = operator+(c1, c2);
    //c4.printCom();

    //步驟3 +替換 函數名
    Complex c4 = c1 + c2;
    c4.printCom();

    //步驟3
    //Complex c4 = c1 / c2;
    //c4.printCom();

    //總結: 1 運算符重載的本質 是 函數調用
    cout<<"hello..."<<endl;

    return ;
}
           

2.限制

16運算符重載運算符重載
16運算符重載運算符重載

3.基礎

16運算符重載運算符重載

例如:

//全局函數 完成 +操作符 重載
Complex operator+(Complex &c1, Complex &c2)
//類成員函數 完成 -操作符 重載
Complex operator-(Complex &c2)
           
  • 運算符重載的兩種方法
16運算符重載運算符重載
16運算符重載運算符重載

例如1:通過類成員函數完成-操作符重載

//函數聲明 Complex operator-(Complex &c2)
//函數調用分析
//用類成員函數實作-運算符重載
    Complex c4 = c1 - c2;
    c4.printCom();
    //c1.operator-(c2);
           

例如2:通過全局函數方法完成+操作符重載

//函數聲明 Complex operator+(Complex &c1, Complex &c2) 
//函數調用分析
int main()
{
        Complex c1(, ), c2(, );
        //Complex c31 = operator+(c1, c2);
Complex c3 = c1 + c2; 
c3.printCom();
}
           
16運算符重載運算符重載

例如3

//前置++操作符 用全局函數實作 
Complex& operator++(Complex &c1) 
{
    c1.a ++;   
    c1.b ++;
    return c1;  
}
           

//調用方法

++c1 ; //=需要寫出操作符重載函數原形 c1.printCom();

//運算符重載函數名定義

//首先承認操作符重載是一個函數 定義函數名

operator++

//分析函數參數 根據左右操作數的個數,

operator++(Complex &c1)

//分析函數傳回值

Complex& operator++(Complex &c1)

傳回它自身

例如4

//4.1前置—操作符 成員函數實作
Complex& operator--()
{
    this->a--;
    this->b--;
    return *this;
}
           

//4.2調用方法

--c1; c1.printCom();

//4.3前置—運算符重載函數名定義

//c1.operator–()

例如5

//5.1 //後置++ 操作符 用全局函數實作
Complex operator++(Complex &c1, int) 
{
    Complex tmp = c1;
    c1.a++;
    c1.b++;
    return tmp;
}
           

//5.2 調用方法

c1 ++ ; //先使用 後++

//5.3 後置++運算符重載函數名定義

Complex operator++(Complex &c1, int)

函數占位參數 和 前置++ 相差別

例如6

//6.1 後置— 操作符 用類成員函數實作
    Complex operator--(int) 
    {
        Complex tmp = *this;
        this->a--;
        this->b--;
        return tmp;
    }
           

//6.2 調用方法

c1 ++ ; //先使用 後++

//6.3 後置–運算符重載函數名定義

Complex operator--(int)

//函數占位參數 和 前置– 相差別

前置和後置運算符總結

C++中通過一個占位參數來區分前置運算和後置運算

#include <iostream>
using namespace std;

class Complex
{
private:
    int a;
    int b;
    //全局函數 重載+運算符
    friend Complex operator+(Complex &c1, Complex &c2);
    //重載 前置++
    friend Complex& operator++(Complex &c1);
    friend Complex operator++(Complex &c1, int);
public:
    Complex(int a=, int b=)
    {
        this->a = a;
        this->b = b;
    }
    void printCom()
    {
        cout<<a<<" + " << b << "i" <<endl;
    }
public:

    //成員函數法 實作 -運算符重載
     Complex operator-(Complex &c2)
    {
        Complex tmp(this->a - c2.a, this->b - c2.b);
        return tmp;
    }

     //前置--
    Complex& operator--()
    {
        this->a --;
        this->b --;
        return *this;
    }

    //後置--
    Complex operator--(int)
    {
        Complex tmp = *this;
        this->a--;
        this->b--;
        return tmp;
    }
};

//全局函數法 實作 + 運算符重載
Complex operator+(Complex &c1, Complex &c2)
{
    Complex tmp(c1.a + c2.a, c1.b + c2.b);
    return tmp;
}

//前置++
Complex& operator++(Complex &c1)
{
    c1.a++;
    c1.b++;
    return c1;
}

//後置++
Complex operator++(Complex &c1, int)
{
    //先使用 在讓c1加加
    Complex tmp = c1;
    //return c1;
    c1.a ++;
    c1.b ++;
    return tmp;
}

/*
全局函數、類成員函數方法實作運算符重載步驟
    1)要承認操作符重載是一個函數,寫出函數名稱
    2)根據操作數,寫出函數參數 
    3)根據業務,完善函數傳回值(看函數是傳回引用 還是指針 元素),及實作函數業務
*/
void main()
{
    Complex c1(, ), c2(, );


    //1 全局函數法 實作 + 運算符重載
    // Complex operator+(Complex &c1, Complex &c2);
    Complex c3 = c1 + c2;
    c3.printCom();

    //2 成員函數 法 實作 -運算符重載
    //c1.operator-(c2);
    //Complex operator-(Complex &c2)
    Complex c4 = c1 - c2;
    c4.printCom();

    //前置++操作符 用全局函數實作
    ++c1;
    c1.printCom();

    //前置--操作符 成員函數方法
    --c1;
    c1.printCom();
    //Complex& operator++(Complex &c1)
    //c1.operator--();

    //後置++操作符 用全局函數實作
    c1++;
    c1.printCom();

    //後置--操作符 用成員函數實作
    c1--;
    c1.printCom();
    //c1.operator--()

    cout<<"hello..."<<endl;
    system("pause");
    return ;
}
           
16運算符重載運算符重載

定義運算符重載函數名的步驟

全局函數、類成員函數方法實作運算符重載步驟

1)要承認操作符重載是一個函數,寫出函數名稱operator+ ()

2)根據操作數,寫出函數參數

3)根據業務,完善函數傳回值(看函數是傳回引用 還是指針 元素),及實作函數業務

運算符重載的正規寫法

#include <iostream>
using namespace std;

/*
class ostream
{

};
*/

class Complex
{
private:
    int a;
    int b;
    //friend void operator<<(ostream &out, Complex &c1);
    friend ostream& operator<<(ostream &out, Complex &c1);

public:
    Complex(int a=, int b=)
    {
        this->a = a;
        this->b = b;
    }
    void printCom()
    {
        cout<<a<<" + " << b << "i" <<endl;
    }
public:

    //實作 + 運算符重載
    Complex operator+(Complex &c2)
    {
        Complex tmp(a + c2.a, b + c2.b);
        return tmp;
    }

    //前置++
    Complex& operator++()
    {
        a++;
        b++;
        return *this;
    }

    //後置++
    Complex operator++(int)
    {
        //先使用 在讓c1加加
        Complex tmp = *this;
        //return c1;
        this->a ++;
        this->b ++;
        return tmp;
    }
    //成員函數法 實作 -運算符重載
     Complex operator-(Complex &c2)
    {
        Complex tmp(this->a - c2.a, this->b - c2.b);
        return tmp;
    }

     //前置--
    Complex& operator--()
    {
        this->a --;
        this->b --;
        return *this;
    }

    //後置--
    Complex operator--(int)
    {
        Complex tmp = *this;
        this->a--;
        this->b--;
        return tmp;
    }
};


void main31()
{
    Complex c1(, ), c2(, );

    //1 全局函數法 實作 + 運算符重載
    // Complex operator+(Complex &c1, Complex &c2);
    Complex c3 = c1 + c2;
    c3.printCom();

    //2 成員函數 法 實作 -運算符重載
    //c1.operator-(c2);
    //Complex operator-(Complex &c2)
    Complex c4 = c1 - c2;
    c4.printCom();

    //前置++操作符 用全局函數實作
    ++c1;
    c1.printCom();

    //前置--操作符 成員函數方法
    --c1;
    c1.printCom();
    //Complex& operator++(Complex &c1)
    //c1.operator--();

    //後置++操作符 用全局函數實作
    c1++;
    c1.printCom();

    //後置--操作符 用成員函數實作
    c1--;
    c1.printCom();
    //c1.operator--()

    cout<<"hello..."<<endl;
    system("pause");
    return ;
}

/*
void operator<<(ostream &out, Complex &c1)
{
    out<<"12345 生活真是苦"<<endl;
    out<<c1.a << " + " << c1.b << "i" << endl;
}
*/

ostream& operator<<(ostream &out, Complex &c1)
{
    out<<"12345 生活真是苦"<<endl;
    out<<c1.a << " + " << c1.b << "i" << endl;
    return out;
}

void main()
{
    int a = ;
    Complex c1(, ), c2(, );
    cout<<a<<endl; //按照資料類型 

    //1
    cout << c1 ;
    //2 ostream 類中 添加 成員函數 .operator<<
    //ostream
    //cout.operator<<(c1);

    //2 函數傳回值當左值 需要傳回一個引用
    cout << c1  << "aaddddd";
    //
    //cout.operator<<(c1) .operator<<("aaddddd");
    //void.operator<<("aaddddd");

    system("pause");
}
           

友元函數實作操作符重載的應用場景

1)友元函數和成員函數選擇方法

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

2)用友元函數 重載 << >>操作符

  • istream 和 ostream 是 C++ 的預定義流類
  • cin 是 istream 的對象,cout 是 ostream 的對象
  • 運算符 << 由ostream 重載為插入操作,用于輸出基本類型資料
  • 運算符 >> 由 istream 重載為提取操作,用于輸入基本類型資料
  • 用友員函數重載 << 和 >> ,輸出和輸入使用者自定義的資料類型

a)用全局函數方法實作 << 操作符

ostream& operator<<(ostream &out, Complex &c1)
{
    //out<<"12345,生活真是苦"<<endl;
    out<<c1.a<<" + "<<c1.b<<"i "<<endl;
    return out;
}
           

//調用方法

cout<<c1;

//鍊式程式設計支援

cout<<c1<<"abcc";

//cout.operator<<(c1).operator<<("abcd");

/函數傳回值充當左值 需要傳回一個引用

b)類成員函數方法無法實作 << 操作符重載

  • 因無法拿到cout這個類的源碼
  • cout.operator<<(c1);

友元函數重載操作符使用注意點

a) 友員函數重載運算符常用于運算符的左右操作數類型不同的情況

16運算符重載運算符重載

b)其他

  • 在第一個參數需要隐式轉換的情形下,使用友員函數重載運算符是正确的選擇
  • 友員函數沒有 this 指針,所需操作數都必須在參數表顯式聲明,很容易實作類型的隐式轉換
  • C++中不能用友員函數重載的運算符有

    = () [] ->

    友元函數案例vector類

#include <iostream>
using namespace std;

//為vector類重載流插入運算符和提取運算符 
class vector
{ 
public :
    vector( int size = ) ;       
    ~vector() ;
    int & operator[]( int i ) ;
    friend ostream & operator << ( ostream & output , vector & ) ;
    friend istream & operator >> ( istream & input, vector & ) ;
private :  
    int * v ;     
    int len ;
};

vector::vector( int size ) 
{ 
    if (size <=  || size >  )
    { 
        cout << "The size of " << size << " is null !\n" ; abort() ;  
    }
    v = new int[ size ] ;  len = size ;
}

vector :: ~vector() 
{ 
    delete[] v ;  
    len =  ; 
}

int &vector::operator[]( int i )        
{ 
    if( i >= && i < len )  return v[ i ] ;
    cout << "The subscript " << i << " is outside !\n" ;  abort() ;
}
ostream & operator << ( ostream & output, vector & ary )
{ 
    for(int i =  ; i < ary.len ; i ++ )  
        output << ary[ i ] << "  " ;
    output << endl ;
    return output ;
}
istream & operator >> ( istream & input, vector & ary ) 
{ 
    for( int i =  ; i < ary.len ; i ++ )  
        input >> ary[ i ] ;
    return  input ;
}

void main()
{ 
    int k ;
    cout << "Input the length of vector A :\n" ;     
    cin >> k ;
    vector A( k ) ;
    cout << "Input the elements of vector A :\n" ;     
    cin >> A ;
    cout << "Output the elements of vector A :\n" ;
    cout << A ;
    system("pause");
}
           

4.提高

1.運算符重載機制

編譯器實作運算符重載實際上就是通過函數重載實作的,可分為全局函數方式,也可分為成員函數方式進行重載,并沒有改變原操作符的屬性和語義。隻是針對某個特定類定義一種新的資料類型操作。

2.重載指派運算符

  • 指派運算符重載用于對象資料的複制
  • operator= 必須重載為成員函數
  • 重載函數原型為:

    類型 & 類名 :: operator= ( const 類名 & ) ;

結論:

1 先釋放舊的記憶體

2 傳回一個引用

3 =操作符 從右向左

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

//

class  Name
{
public:
    Name(const char *myp)
    {
        m_len = strlen(myp);
        m_p =(char *) malloc(m_len + ); //
        strcpy(m_p, myp);
    }

    //Name obj2 = obj1;
    //解決方案: 手工的編寫拷貝構造函數 使用深copy
    Name(const Name& obj1)
    {
        m_len = obj1.m_len;
        m_p = (char *)malloc(m_len + );
        strcpy(m_p, obj1.m_p);
    }

    //obj3 = obj1;  // C++編譯器提供的 等号操作 也屬 淺拷貝
    //obj3.operator=(obj1)

    Name& operator=(Name &obj1)
    {
        //先釋放舊的記憶體
        if (this->m_p != NULL)
        {
            delete[] m_p;
            m_len = ;
        }
        //2 根據obj1配置設定記憶體大小
        this->m_len = obj1.m_len;
        this->m_p = new char [m_len+];

        //把obj1指派
        strcpy(m_p, obj1.m_p);
        return *this;
    }

    ~Name()
    {
        if (m_p != NULL)
        {
            free(m_p);
            m_p = NULL;
            m_len = ;
        }
    }
protected:
private:
    char *m_p ;
    int m_len; 
};

//對象析構的時候 出現coredump
void objplaymain()
{
    Name obj1("abcdefg");
    Name obj2 = obj1;  //C++編譯器提供的 預設的copy構造函數  淺拷貝
    Name obj3("obj3");

    obj3 = obj1;  // C++編譯器提供的 等号操作 也屬 淺拷貝
    //obj3.operator=(obj1)
    //operato=(Name &obj1)

    obj1 = obj2 = obj3;
    //obj2.operator=(obj3);
    //obj1 = void;
}

void main()
{
    objplaymain();
    cout<<"hello..."<<endl;
    system("pause");
    return ;
}
           

3.重載下标運算符

  • [ ]運算符用于通路資料對象的元素
  • 重載格式

    類型 類 :: operator[] ( 類型 ) ;

  • 隻能用成員函數重載,不能用友元函數重載

示例:

設 x 是類 X 的一個對象,則表達式

x [ y ]

可被解釋為

x . operator [ ] ( y )

16運算符重載運算符重載
16運算符重載運算符重載
函數傳回值當左值需要傳回一個引用!

4.帶下标和相等操作符的數組類

  • 類的頭檔案
#ifndef NEWARRAY_H
#define NEWARRAY_H
#include <iostream>
#include <stdlib.h>

class NewArray
{
public:
    NewArray();
    NewArray(int _len);
    NewArray(const NewArray & obj);
    ~NewArray();

    void setData(int index,int var);
    int getData(int index);
    int length();

    int& operator[](int i);
    NewArray& operator=(NewArray& obj);
    bool operator==(NewArray& obj);
    bool operator!=(NewArray& obj);

private:
    int m_len;
    int *m_buf;
};

#endif // NEWARRAY_H
           
  • 類的實作檔案
#include "newarray.h"

NewArray::NewArray()
{
    m_buf = NULL;
    m_len = -;
}

NewArray::NewArray(int _len)
{
    if(_len < )
        _len = ;
    m_len = _len;
    m_buf = new int[m_len];

}
NewArray::NewArray(const NewArray & obj)
{
    m_len = obj.m_len;
    m_buf = new int[m_len];
    for(int i = ;i < m_len;i++)
    {
        m_buf[i] = obj.m_buf[i];
    }
}
NewArray::~NewArray()
{
    if(m_buf != NULL)
    {
        delete []m_buf;
        m_buf = NULL;
        m_len = -;
    }
}

void NewArray::setData(int index,int var)
{
    m_buf[index] = var;
}
int NewArray::getData(int index)
{
    return  m_buf[index];
}
int NewArray::length()
{
    return m_len;
}

int& NewArray::operator[](int i)
{
    return m_buf[i];
}
NewArray& NewArray::operator=(NewArray& obj)
{
    if(m_buf != NULL)
    {
        delete []m_buf;
        m_len = -;
        m_buf = NULL;
    }
    m_len = obj.m_len;
    m_buf = new int[m_len];
    for(int i = ;i < m_len;i++)
    {
        m_buf[i] = obj.m_buf[i];
    }
    return *this;

}
bool NewArray::operator==(NewArray& obj)
{
    if(m_len != obj.m_len)
    {
        return false;
    }
    for(int i = ;i < m_len;i++)
    {
        if(m_buf[i] != obj.m_buf[i])
        {
            return false;
        }
    }

    return true;
}
bool NewArray::operator!=(NewArray& obj)
{
    return !((*this) == obj);
}
           
  • 測試檔案
#include "newarray.h"
using namespace std;



int main()
{
    NewArray  a1();

    for (int i=; i<a1.length(); i++)
    {
        //成員函數方式指派
        a1.setData(i, i);
        //下标運算符重載指派
        a1[i] = i;

        //函數傳回值當左值,需要傳回一個引用
        //a1.operator [i]
    }

    cout<<"\na1: ";
    for (int i=; i<a1.length(); i++)
    {
        //cout<<a1.getData(i)<<" ";//成員函數方式擷取元素
        //下标運算符方式擷取數組元素
        cout<<a1[i]<<"\t";
    }
    cout<<endl;

    //指派運算符重載
    NewArray a2 = a1;
    cout<<"\na2: ";
    for (int i=; i<a2.length(); i++)
    {
        cout<<a2.getData(i)<<" ";
    }
    cout<<endl;

    //3
    NewArray a3();
    {
        a3 = a1;
        a3 = a2 = a1;

        cout<<"\na3: ";
        for (int i=; i<a3.length(); i++)
        {
            cout<<a3[i]<<" ";
        }


    }


    //功能4

    if (a3 == a1)
    {
        printf("\nequal\n");
    }
    else
    {
        printf("\nnot equal\n");
    }
    //a3.operator==(a1);
    //bool operator==(Array &a1);


    if (a3 != a1)
    {
        printf("\nnot equal\n");
    }
    else
    {
        printf("\nequal\n");
    }
    //
    //a3.operator!=(a1)
    // bool operator!=(Array &a1);


    cout<<"hello..."<<endl;

    return ;
}
           

5.重載函數調用運算符

  • () 運算符用于函數調用
  • 重載格式

    類型 類 :: operator() ( 表達式表 ) ;

  • 隻能用成員函數重載,不能用友元函數重載

例1

設 x 是類 X 的一個對象,則表達式

x ( arg1, arg2, … )

可被解釋為

x . operator () (arg1, arg2, … )

案例:

  • 例:用重載()運算符實作數學函數的抽象
#include <iostream>
class  F
  { public :  
        double  operator ( )  ( double x ,  double  y ) ;
  } ;
double  F :: operator ( )  ( double  x ,  double  y )
   { return   x * x + y * y ; }
void main ( )           
{ 
F  f  ;
f.getA();
    cout << f (  ,  ) << endl ;  // f . operator() (5.2, 2.5)
}
           
  • 例3 用重載()運算符實作 pk 成員函數
#include <iostream.h>
class  F
  { public :  
        double  memFun ( double x ,  double  y ) ;
  } ;
double  F :: memFun ( double  x ,  double  y )
   { return   x * x + y * y ; }
void main ( )           
{ 
F  f  ;
    cout << f.memFun (  ,  ) << endl ;
}
           

6.不建議重載的運算符

理論知識:

1)&&和||是C++中非常特殊的操作符

2)&&和||内置實作了短路規則

3)操作符重載是靠函數重載來完成的

4)操作數作為函數參數傳遞

5)C++的函數參數都會被求值,無法實作短路規則

#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
    int i;
public:
    Test(int i)
    {
        this->i = i;
    }

    Test operator+ (const Test& obj)
    {
        Test ret();

        cout<<"執行+号重載函數"<<endl;
        ret.i = i + obj.i;
        return ret;
    }

    bool operator&& (const Test& obj)
    {
        cout<<"執行&&重載函數"<<endl;

        return i && obj.i;
    }
};

// && 從左向右
void main()
{
    int a1 = ;
    int a2 = ;

    cout<<"注意:&&操作符的結合順序是從左向右"<<endl;

    if( a1 && (a1 + a2) )
    {
        cout<<"有一個是假,則不在執行下一個表達式的計算"<<endl;
    }

    Test t1 = ;
    Test t2 = ;

    //if( t1 && (t1 + t2)  )
    //t1  && t1.operator+(t2)
    // t1.operator&&(  t1.operator+(t2) )   

    //1 && || 重載他們 不會産生短路效果
    if(  (t1 + t2) && t1)
    {
        //t1.operator+(t2) && t1;
        //(t1.operator+(t2)).operator&&(t1);

        cout<<"兩個函數都被執行了,而且是先執行了+"<<endl;
    }

    //2 && 運算符的結合性
    // 兩個邏輯與運算符  在一塊的時候, 采去談 運算符的結合性
    // 從左到右    (t1 + t2) && t1 ; 運算結果 && t2)
    //if(  (t1 + t2) && t1 && t2)
    {
        //t1.operator+(t2) && t1;
        //(t1.operator+(t2)).operator&&(t1);

        cout<<"兩個函數都被執行了,而且是先執行了+"<<endl;
    }

    system("pause");
    return ;
}
           

5.字元串類的實作

  • 頭檔案
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
using namespace std;
#include <stdlib.h>
#include <string.h>
class MyString
{
public:
    MyString();
    MyString(int _len);
    MyString(const char *_str);
    MyString(const MyString & obj);
    ~MyString();


    MyString& operator =(const MyString & obj);
    MyString& operator =(const char * _str);

    bool operator ==(const MyString & obj);
    bool operator ==(const char * _str);

    bool operator !=(const MyString & obj);
    bool operator !=(const char * _str);

    bool operator >(const MyString & obj);
    bool operator >(const char * _str);

    bool operator <(const MyString & obj);
    bool operator <(const char * _str);

    char& operator [](int index);

    friend ostream& operator<<(ostream & out,MyString & obj);
    friend istream& operator>>(istream & in,MyString & obj);



private:
    int m_len;
    char *m_str;
};

#endif // MYSTRING_H
           
  • 實作檔案
#include "mystring.h"

MyString::MyString()
{
    m_len = ;
    m_str = NULL;
}
MyString::MyString(int _len)
{
    if(_len < )
        _len = ;
    m_len = _len;
    m_str = new char[m_len+];
    memset(m_str,,m_len);
}

MyString::MyString(const char *_str)
{
    if(_str == NULL)
    {
        m_len = ;
        m_str = new char[m_len+];
        strcpy(m_str,"");
    }else
    {
        m_len = strlen(_str);
        m_str = new char[m_len+];
        strcpy(m_str,_str);
    }

}
MyString::MyString(const MyString & obj)
{
    m_len = obj.m_len;
    m_str = new char[m_len+];
    strcpy(m_str,obj.m_str);
}
MyString::~MyString()
{
    if(m_str != NULL)
    {
        delete []m_str;
        m_str = NULL;
        m_len = ;
    }
}

MyString& MyString::operator =(const MyString & obj)
{
    if(m_str != NULL)
    {
        delete []m_str;
        m_str = NULL;
        m_len = ;
    }
    m_len = obj.m_len;
    m_str = new char[m_len+];
    strcpy(m_str,obj.m_str);
    return *this;
}

MyString& MyString::operator =(const char * _str)
{
    if(m_str != NULL)
    {
        delete []m_str;
        m_str = NULL;
        m_len = ;
    }

    if(_str == NULL)
    {
        m_len = ;
        m_str = new char[m_len+];
        strcpy(m_str,"");
    }else
    {
        m_len = strlen(_str);
        m_str = new char[m_len+];
        strcpy(m_str,_str);
    }

    return *this;
}

bool MyString::operator ==(const MyString & obj)
{
    if(m_len != obj.m_len)
    {
        return false;
    }
    return !strcmp(m_str,obj.m_str);

}

bool MyString::operator ==(const char * _str)
{
    if(_str == NULL)
    {
        if(m_len == )
        {
            return true;
        }else{

            return false;
        }
    }else{
        if(m_len == strlen(_str)){
            return !strcmp(m_str,_str);
        }else{
            return false;
        }
    }


}

bool MyString::operator !=(const MyString & obj)
{
    return !((*this) == obj);
}

bool MyString::operator !=(const char * _str)
{
    return !((*this) == _str);
}

bool MyString::operator >(const MyString & obj)
{
    if(strcmp(m_str,obj.m_str) > )
    {
        return true;
    }else{
        return false;
    }
}

bool MyString::operator >(const char * _str)
{
    if(strcmp(m_str,_str) > )
    {
        return true;
    }else{
        return false;
    }
}

bool MyString::operator <(const MyString & obj)
{
    if(strcmp(m_str,obj.m_str) < )
    {
        return true;
    }else{
        return false;
    }
}

bool MyString::operator <(const char * _str)
{
    if(strcmp(m_str,_str) < )
    {
        return true;
    }else{
        return false;
    }
}

char& MyString::operator [](int index)
{
    return m_str[index];
}

ostream& operator<<(ostream & out,MyString & obj)
{
    out<<obj.m_str;
    return out;
}

istream& operator>>(istream & in,MyString & obj)
{
    in>>obj.m_str;
    return in;
}
           
  • 測試檔案
#define _CRT_SECURE_NO_WARNINGS

#include "mystring.h"



void main01()
{
    MyString s1;
    MyString s2("s2");
    MyString s2_2 = NULL;
    MyString s3 = s2;
    MyString s4 = "s4444444444";

    //測試運算符重載 和 重載[]
    //=

    s4 = s2;
    s4 = "s2222";
    s4[] = '4';
    printf("%c", s4[]);

    cout<<s4 <<endl;
    //ostream& operator<<(ostream &out, MyString &s)

    //char& operator[] (int index)
    //MyString& operator=(const char *p);
    //MyString& operator=(const MyString &s);

    cout<<"hello..."<<endl;
    system("pause");
    return ;
}

void main02()
{
    MyString s1;
    MyString s2("s2");

    MyString s3 = s2;

    if (s2 == "aa")
    {
        printf("相等");
    }
    else
    {
        printf("不相等");
    }

    if (s3 == s2)
    {
        printf("相等");
    }
    else
    {
        printf("不相等");
    }

}
void main03()
{
    MyString s1;
    MyString s2("s2");

    MyString s3 = s2;
    s3 = "aaa";

    if (s3 < "bbbb" )
    {
        printf("s3 小于 bbbb");
    }
    else
    {
        printf("s3 大于 bbbb");
    }

    MyString s4 = "aaaaffff";
    //strcpy(s4.c_str(), "aa111"); //MFC
    cout<<s4<<endl;
}

void main011()
{
    MyString s1();
    cout<<"\n請輸入字元串(回車結束)";
    cin>>s1;

    cout<<s1;
    system("pause");

}

int main()
{
    MyString s1();
    cout<<"\n請輸入字元串(回車結束)";
    cin>>s1;

    cout<<s1<<endl;

    system("pause");

    return ;

}
           
總結
  • 操作符重載是C++的強大特性之一
  • 操作符重載的本質是通過函數擴充操作符的語義
  • operator關鍵字是操作符重載的關鍵
  • friend關鍵字可以對函數或類開發通路權限
  • 操作符重載遵循函數重載的規則
  • 操作符重載可以直接使用類的成員函數實作
  • =, [], ()和->操作符隻能通過成員函數進行重載
  • ++操作符通過一個int參數進行前置與後置的重載
  • C++中不要重載&&和||操作符

附錄:運算符和結合性

16運算符重載運算符重載
16運算符重載運算符重載