C++運算符重載

推薦資料

https://www.cnblogs.com/xiaokang01/p/9865724.htmlhtml

運算符重載

什麼是運算符重載ios

運算符重載的本質是一個函數c++

運算符重載的做用

1爲何會用運算符重載機制
用複數類舉例
//Complex c3 = c1 + c2;
//緣由 Complex是用戶自定義類型,編譯器根本不知道如何進行加減
//編譯器給提供了一種機制,讓用戶本身去完成,自定義類型的加減操做。。。。。
//這個機制就是運算符重載機制

運算符重載入門

#include <iostream>

using namespace std;

class Complax
{
public:
    Complax(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    void printC()
    {
        cout << "a = " << a << "\tb = " << b << endl;
    }
    ~Complax()
    {
    }
//private:
public:

    int a;
    int b;

};
// 1定義全局函數
Complax myAdd(Complax &c1, Complax &c2)
{
    Complax temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}
// 2函數名升級
Complax operator+(Complax &c1, Complax &c2)
{
    Complax temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}
int main01()
{
    int a = 0, b = 0;
    int c; // 基礎性數據類型,編譯器已經知道了,如何運算
    c = a + b;

    // a + bi;  // 複數運算規則
    Complax c1(1, 2), c2(3, 4);
    Complax c3;  // 2c3是用戶自定義數據類型,c++編譯器不知道如何運算
//    c3 = c1 + c2;

    // 3c++編譯器應該給咱們提供一種機制
    // 讓自定義數據類型 有機會進行 運算符操做 ==> 運算符重載

    // 4運算符重載機制
    Complax c4 = myAdd(c1, c2);
    c4.printC();

    // 步驟二:Complax c4 = c1+c2;
    // Complax c5 = operator+(c1, c2);
    // c5.printC();

    // 步驟三:
    Complax c5 = c1 + c2;
    c5.printC();

    // 運算符重載的本質 是  函數調用
    return 0;
}
View Code

 

運算符重載的限制

運算符重載基礎

運算符重載的方法步驟

全局函數、類成員函數方法實現運算符重載步驟
1)要認可操做符重載是一個函數,寫出函數名稱operator+ ()
2)根據操做數,寫出函數參數
3)根據業務,完善函數返回值(看函數是返回引用 仍是指針 元素),及實現函數業務
#include <iostream>
using namespace std;

class Complax
{
private:
    int a;
    int b;
    // 重載友元函數 全局函數 操做符重載
    friend Complax operator+(Complax &c1, Complax &c2);
public:
    Complax(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    void printC()
    {
        cout << "a = " << a << "\tb = " << b << endl;
    }
    // 2成員函數法 實現 - 運算符重載
    Complax operator-(Complax &c2)
    {
//        this->a -= c2.a;
//        this->b -= c2.b;
//        return *this;  // 這一個會改變c1的值,由於是+=
        Complax temp(this->a - c2.a, this->b -c2.b);
        return temp;

    }

};
// 1全局函數法 實現 + 運算符重載
Complax operator+(Complax &c1, Complax &c2)
{
    Complax temp(c1.a+c2.a, c1.b+c2.b);
    return temp;
}
/*
    全局函數,類成員函數方法實現運算符重載步驟
    1:要認可運算符重載是一個函數, 寫出函數名稱
    2: 根據操做數,寫出函數參數
    3:根據業務,完善函數的返回值(看函數返回引用,元素,指針),及實現函數業務
*/
int main()
{
    Complax c1(1, 2), c2(3, 4);

    // 1全局函數法 實現 - 運算符重載
    // Complax operator+(Complax &c1, Complax &c2)
    Complax c3 = c1 + c2;
    c3.printC();

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

    return 0;
}
運算符重載的兩種方法

 

重載++ 須要注意

#include <iostream>
using namespace std;

class Complax
{
private:
    int a;
    int b;
    // 1全局函數法 實現 ++ 運算符重載
    friend Complax& operator++(Complax &c1);  // 這裏是返回一個引用注意,前置++
    friend Complax operator++(Complax &c2, int); // 後置++

public:
    Complax(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }

    // 前置--
    // 由於前置返回的是自己,因此返回一個引用
    // Complax& operator--(Complax &c1)  這個是寫錯的,注意錯在哪裏
    Complax& operator--()
    {
        this->a --;
        this->b --;
        return *this;
    }

    // 後置--  由於後置返回的是一個副本因此不用 返回引用
    Complax operator--(int)
    {
        Complax tem = *this;
        this->a--;
        this->b--;
        return tem;
    }

    void printC()
    {
        cout << "a = " << a << "\tb = " << b << endl;
    }
};



// 特別注意 只有成員函數纔有 this指針
// 1全局函數法 實現 前置++ 運算符重載
Complax& operator++(Complax &c1)
{
    c1.a++;
    c1.b++;
    return c1;
}
// 後置++
Complax operator++(Complax &c2, int) // int防止與前置++重載而加的佔位符
{
    // 由於後置++是使用, 在讓c2++因此要定義一個臨時變量
    Complax tem = c2;
    c2.a++;
    c2.b++;
    return tem;
}


int main()
{
    Complax c1(1, 2), c2(30, 40);

    // 1全局函數法 實現 前置++ 運算符重載
    //   Complax& operator++(Complax &c1);
    ++c1;  // 至關於 operator++(c1);
    c1.printC();

    // 2成員函數 實現 前置-- 運算符重載
    // 至關於c2.operator--();
    --c2;
    c2.printC();

    //  1全局函數法 實現 後置++ 運算符重載
    // operator++(c2);
    c2++;
    //  Complax& operator++(Complax &c1);  前置++
    //  Complax operator++(Complax &c2, int); // int防止與前置++重載而加的佔位符
    c2.printC();

    // 2成員函數 實現 後置-- 運算符重載
    // 至關於c2.operator--();
    // Complax operator--(int) 函數原型
    c1--;
    c1.printC();

    return 0;
}
++重載例子

 

友元函數 重載 <<  還有鏈式編程 

//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);

注意點編程

友員函數重載運算符經常使用於運算符的左右操做數類型不一樣的狀況
在第一個參數須要隱式轉換的情形下,使用友員函數重載運算符是正確的選擇
友員函數沒有 this 指針,所需操做數都必須在參數表顯式聲明,很容易實現類型的隱式轉換
C++中不能用友員函數重載的運算符有
= () [] ->


因此這個能夠在寫一個operator + 或者寫一個友元函數重載

簡單版的複數類重載

#include <iostream>

using namespace std;

class Complax
{
private:
    int a;
    int b;
    friend ostream& operator<<(ostream &out, const Complax &c1);
public:
    Complax(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    // +運算符重載
    Complax operator+(Complax &c2)
    {
        Complax tem(this->a + c2.a, this->b + c2.b);
        return tem;
    }
    // -運算符重載
    Complax operator-(Complax &rhl)
    {
        Complax tem(this->a - rhl.a, this->b - rhl.b);
        return tem;
    }
    // 前置--
    Complax& operator--()
    {
        this->a --;
        this->b --;
        return *this;
    }
    // 前置++
    Complax& operator++()
    {
        this->a++;
        this->b++;
        return *this;
    }

    // 後置--  由於後置返回的是一個副本因此不用 返回引用
    Complax operator--(int)
    {
        Complax tem = *this;
        this->a--;
        this->b--;
        return tem;
    }
    // 後置++
    Complax operator++(int)
    {
        Complax tem = *this;
        this->a++;
        this->b++;
        return tem;
    }
    void printC()
    {
        cout << "a = " << a << "\tb = " << b << endl;
    }
};


// 這裏的ostream 不能加const
ostream& operator<<(ostream &out, const Complax &c1)
{
    cout <<"重載<<運算符 鏈式輸出";
    out << "c1.a = " << c1.a << "\t c1.b = " << c1.b << endl;
}
// 在<< 和 >> 運算符重載時 只能使用全局函數就是 加個友元聲明
int main32()
{
    Complax c1(1, 2), c2(30, 40);
    int a = 10;
    cout << a << endl; // 基本數據類型

    // 自定義數據類型
    cout << c1;
    // 全局函數調用方法
    // operator<<(cout ,c1);
    // 函數類型聲明
    // friend void operator<<(const ostream &out, const Complax &c1);

    cout << c2;
    // 成員函數調用方法  在ostream類中添加 成員函數 operator<<
    // 可是ostream類的源碼拿不到,因此在這種狀況下只能使用友元函數
    // cout.operator<<(c2);


    // 最好都寫這一個
    cout <<c1 << "sflkasdf";
    // cout.operator<< (c1).operator<<("slkfdkls");
    // 上式等價於 void.operator<<"slkfdls"; 因此
    // 若是鏈式輸入的話
    // 就要把返回時改成ostroam &;



    return 0;
}
int main031()
{
    Complax c1(1, 2), c2(30, 40);
    // 後置++
    c1++;
    c1.printC();
    // 前置++
    ++c2;
    c2.printC();   // 雖然最後結果顯示都是同樣的,可是調用的不同,
                  // 由於printC函數輸入的是前置,或後置以後的結果因此會輸出相同

    //+運算符重載
    Complax c3 = c1 + c2;
    c3.printC();

    // -運算符重載
    Complax c4 = c3 - c1;
    c4.printC();

    cout << "Hello world!" << endl;
    return 0;
}
簡單的複數類重載

簡單的name類編寫

有深拷貝ide

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class Name
{
public:

    Name (const char *mp)
    {
        len = strlen(mp);
        p = (char *)malloc(sizeof(len+1)); // 注意細節
        strcpy(p, mp);

    }

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

    // 成員函數 =運算符重載  不能寫全局函數
    Name& operator=(const Name &obj)
    {
        // 先釋放舊的內存  特別注意
        if(p != NULL)
        {
            delete []p;
            len = 0;
        }
        len = obj.len;
        p = new char[len+1];
        strcpy(p, obj.p);
        return *this;
    }
    ~Name ()
    {
        cout << "\t析構函數" << endl;
        if (p != NULL)
        {
            free(p);
            p = NULL;
            len = 0;
        }
    }
    void printName()
    {
        cout <<"\tp = " << this->p << "\t len = " << this->len << endl;
    }
private:
    char *p;
    int len;
};


// 對象析構的時候會出現,錯誤
// 調試存在bug
// 析構的時候會出現二次釋放
//默認的拷貝構造函數,若是要對指針進行拷貝,則只是淺拷貝,拷貝事後是兩個變量指向
//同一段內存,釋放拷貝的obj2後,obj1的指針就是垃圾值,在釋放就會出錯

void objmain()
{
    Name obj1("aaaa");
    Name obj2 = obj1;
    Name obj3("sfs");

    //  obj3 = obj1;  // 等號操做 c++編譯器會對=進行默認的重載(一樣會發生二次釋放的問題)
    // 就須要手動的寫 operator= 函數

    cout << "成員函數=重載  ";
    obj3 = obj1;
    obj3.printName();
    // obj3.operator=(const Name & obj1);
    // void operator=(const Name &obj)  // 函數聲明
    // 若是要執行 obj3 = obj2 = obj1; 就須要把void 改爲 Name&
    {
        obj3 = obj2 = obj1;
        obj3.printName();
        obj2.printName();
        obj1.printName();
    }

}

int main04()
{
    objmain();
}

// 重載 = 運算符注意點
// 1 先把舊的內存釋放
// 2 返回一個引用 obj3 = obj1 = obj2;
// 3數據進行拷貝
name

 

編寫複數類

#include <iostream>
//#include "Complex.h"
#include "Complex.cpp"
using namespace std;
// 須要注意的是 若是是在main中包含complex.cpp的話,就要在complex.cpp的函數
// 寫成內聯函數, 而且在其中寫上#include"Complex.h"  推薦
// 或者在main中包含#include"Complex.h", 而後再complex.h中包含#include"Complex.cpp"

// Complex類
int main() {
    std::cout << "Hello, World!" << std::endl;
    Complex c(2, 3);
    Complex c2(3, 4);
    c += c2;
    c -= c2;
    Complex c3 = c2;  // 調用拷貝構造函數
    c3 = c;    // 運算符重載
    cout << c3 << endl;
    Complex c4 = c + c2;
    c2++;
    cout << c << c2 << endl;
    c == c2;
    cout << sizeof(c)<<endl;   // 16個字節

//    cout << c.real() << "i+"<< c.imge() << endl;

    return 0;
}
main.cpp
//
// Created by lk on 18-5-28.
//

#ifndef HOUJIE_COMPLEX_H    // 防衛式聲明
#define HOUJIE_COMPLEX_H

#include <iostream>

class Complex {
public:

    Complex(double re = 0, double im = 0)
            : re(re), im(im) {}

    // 拷貝構造函數
    Complex(const Complex &obj)
            : re(obj.re), im(obj.im) {}

    Complex operator+(const Complex &obj);

    Complex operator-(const Complex &obj);

    Complex &operator+=(const Complex &obj);

    Complex &operator-=(const Complex &obj);

    bool operator==(const Complex &obj);

    Complex &operator--();

    Complex &operator++();

    Complex operator--(int);

    Complex operator++(int);


    double real() { return re; }

    double imge() { return im; }

private:
    double re;
    double im;

    friend std::ostream &operator<<(std::ostream &os, Complex &obj);

};


#endif //HOUJIE_COMPLEX_H
Complex.h
//
// Created by lk on 18-5-28.
//

#include "Complex.h"
#include <iostream>
inline
Complex &Complex::operator+=(const Complex &obj) {
    this->re += obj.re;
    this->im += obj.im;
    return *this;
}
inline
Complex &Complex::operator-=(const Complex &obj) {
    this->im -= obj.im;
    this->re -= obj.re;
    return *this;
}

// 前置--  --c
inline
Complex &Complex::operator--() {
    this->im--;
    this->re--;
    return *this;
}

// 前置++ ++c
inline
Complex &Complex::operator++() {
    this->im++;
    this->re++;
    return *this;
}

// 後置--  由於後置返回的是一個副本因此不用返回引用 c--
inline
Complex Complex::operator--(int) {
    Complex tem = *this;
    this->im--;
    this->re--;
    return tem;
}

// 後置++ c++
inline
Complex Complex::operator++(int) {
    Complex tem = *this;
    this->im++;
    this->re++;
    return tem;
}

// 重載+  調用者 c+c2
// 這是類內函數, 用一個參數, 若是是類外的就要用兩個參數
inline
Complex Complex::operator+(const Complex &obj) {
    return Complex(this->im + obj.im, this->re + obj.re);
}


// 重載-  調用者 c-c2
inline
Complex Complex::operator-(const Complex &obj) {
    Complex tem(this->im - obj.im, this->re - obj.re);
    return tem;
}

// 重載 == c == c2
inline
bool Complex::operator==(const Complex &obj) {
    return (this->im == obj.im && this->re == obj.re);
}

// 重載<< cout << c
inline
std::ostream &
operator<<(std::ostream &os, Complex &obj) {
    return os << obj.re << obj.im;
}
Complex.cpp

 

編寫string類

#if 0
#include <iostream>
//#include "MyString.h"
#include "MyString.cpp"
using namespace std;

int main()
{
    MyString s("aaa");
    MyString s2(10);
    s2 = s;
    cout << s  << s2 << endl;
    if (s == s2)
    {
        cout << "s == s2" << endl;
    }
    else
        cout << "s != s2 "<< endl;
    if (s == "aab")
        cout << "s == aab" << endl;
    if (s != "aab")
        cout << "s != aab" << endl;
    s2 = "abbb00";
    auto t = s > "abb00";
    cout << t << endl;
    cout << s[2] << endl;
//    cin >> s;
//    cout << s;
    MyString s3 = "sjkf";
    s3 = s2;
    cout << s3 ;
    return 0;
}
#endif

#include <iostream>
#include <cstring>
#include "MyString.cpp"

using namespace std;

int main1() {
    // 這裏也是一個功能
    MyString s1(10);
    cout << "請輸入s1" << endl;

    // 重載 >>
    cin >> s1;
    cout << s1 << endl;

    return 0;
}

int main2() {
    MyString s1;
    MyString s2("ab");

    MyString s3(s2);
    s3 = "abcd";

    int flag = (s3 < "bbbb");
    {
        if (flag > 0)
            cout << "s3 > bbbb " << endl;

        else if (flag == 0)
            cout << "s3 = bbbb " << endl;

        else
            cout << "s3 < bbbb " << endl;
    }

    MyString s4 = "abcds";
    cout << s4 << endl;

    return 0;
}

int main() {
    MyString s1;
    MyString s2("aaa");
    MyString s3(s1);  // MyString s3 = s1;
    MyString s4("s4444");


    // 運算符重載 =
    // MyString& operator=(MyString & rhs); 函數原型調用s4.operator=(MyString & rhs)
    s4 = s2;

    // 也是調用運算符重載 MyString& operator=(const char *p);
    s4 = "2222";

    s4[0];   // 因此說 []重載時 最後是返回一個引用
    cout << "當右值 s4[0] = " << s4[0] << endl;

    s4[0] = 'a';
    cout << "當左值 s4[0] = " << s4[0] << endl;

    // s4.operator[](int index);
    // char& operator[](int index)  // 當左值,當右值


    // << 重載
    cout << s4 << endl;
    // MyString& operator<<(ostream &out, MyString &rhs)


    // == 重載
    if (s2 == "aaa") {
        cout << "相等" << endl;
    } else {
        cout << "不相等" << endl;
    }

    // if (s2 != "abcd")
    //  s2.operator==(const char *p)
    //  bool operator==(const char *p)

    if (s2 == s4) {
        cout << "相等" << endl;
    } else {
        cout << "不相等" << endl;
    }
    // if (s2 != s4)

    // bool operator==(const MyString &rhs)

    cout << "Hello world!" << endl;
    return 0;
}
main.cpp
//
// Created by lk on 18-6-10.
//

#ifndef CESHI_MYSTRING_H
#define CESHI_MYSTRING_H

#include <cstring>
#include <iostream>

using namespace std;

class MyString {
    friend ostream &operator<<(ostream &out, const MyString &obj);

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

public:
    // 構造
    MyString();

    MyString(const char *data);

    MyString(const int leng);

    // 拷貝構造
    MyString(const MyString &obj);

    ~MyString();

public:
    MyString &operator=(const MyString &obj);

    MyString &operator=(const char *data);

    bool operator==(const MyString &obj) const;  // const表示this->m_data不能修改
    bool operator!=(const MyString &obj) const;

    bool operator==(const char *data) const;

    bool operator!=(const char *data) const;

public:
    int operator>(const MyString &obj) const;

    int operator<(const MyString &obj) const;

    int operator>(const char *data) const;

    int operator<(const char *data) const;

public:

    char &operator[](const int index) const;

private:
    char *m_data;
    int len;
};

#endif //CESHI_MYSTRING_H
MyString.h
//
// Created by lk on 18-6-10.
//
#include "MyString.h"

//#include <cstring>
// 無參構造函數
inline MyString::MyString() {
    len = 0;
    m_data = new char[1];
    strcpy(m_data, "");
}

inline MyString::MyString(const char *data) {
    // 若是有初始值
    if (data) {
        len = strlen(data);
        m_data = new char[len + 1];
        strcpy(m_data, data);
    } else {
        len = 0;
        m_data = new char[1];
        strcmp(m_data, "");
    }

}

inline MyString::  //構造一個空串
MyString(const int leng) {
    /*
        if (len == 0)
        {
            m_len = 0;
            m_p = new char[m_len + 1];
            strcpy(m_p, "");
        }
        else
        {
            m_len = len;
            m_p = new char[m_len + 1];
            // strcpy(m_p, "");  哪個都行
            memset(m_p, 0, m_len);
        }

    */
    len = leng;
    m_data = new char[len + 1];
    strcpy(m_data, "");  // 構造空串
}


// MyString s1 = s2; 拷貝構造
inline MyString::
MyString(const MyString &obj) {
    len = strlen(obj.m_data);
    m_data = new char[len + 1];
    strcpy(m_data, obj.m_data);

}

// 析構函數
inline MyString::~MyString() {
    if (m_data != NULL) {
        len = 0;
        delete[]m_data;
        this->m_data = NULL;   // 防止出現野指針
    }
}

// s1 = s2 = s3; 拷貝賦值
inline MyString &MyString::operator=(const MyString &obj) {
    // 提升水平的判斷, 就是若是是本身賦值給本身的話,就要加上這句,必須加
    // 若是this 等於obj對象的指針,  這裏的&是取地址
    if (this == &obj) {
        return *this;
    }
    // 釋放舊內存
    if (m_data != NULL) {
        len = 0;
        delete[]m_data;
        m_data = NULL;
    }

    // 分配新內存 並賦值
    len = strlen(obj.m_data);
    m_data = new char[len + 1];
    strcpy(m_data, obj.m_data);

    return *this;
}

// 拷貝賦值 s1 ="aaa"
inline MyString &MyString::operator=(const char *data) {
//    if (data != NULL)
    // 釋放舊內存
    if (m_data == NULL) {
        delete[]m_data;
        len = 0;
        m_data = NULL;
    }
    // 分配新內存
    if (data == NULL) {
        len = 0;
        m_data = new char[1];
        strcpy(m_data, "");
    } else {
        len = strlen(data);
        m_data = new char[len + 1];
        strcpy(m_data, data);
    }
    return *this;


}

inline bool
MyString::operator==(const MyString &obj) const {
    if (len != obj.len)
        return false;
    else {
        if (!strcmp(m_data, obj.m_data))
            return true;
        else
            return false;

    }
}

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

inline bool
MyString::operator==(const char *data) const {
    if (strlen(data) != len) {
        return false;
    } else {
        if (!strcmp(data, m_data))
            return true;
        return false;
    }
}

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

inline int
MyString::operator<(const MyString &obj) const {
    return strcmp(m_data, obj.m_data);
}

inline int
MyString::operator>(const MyString &obj) const {
    return strcmp(obj.m_data, m_data);
}

inline int
MyString::operator>(const char *data) const {
    return strcmp(m_data, data);
}

inline int
MyString::operator<(const char *data) const {
    return strcmp(data, m_data);
}

// s[2]
inline char &   // 多看
MyString::operator[](const int index) const {
    static char sNull = '\0';
    if (strlen(m_data) > index + 1 && index >= 0)
        return m_data[index];
    else {
        cout << "下標越界" << endl;
        return sNull;
    }
}


// << 重載 應該是友元 注意返回值,
// cout << s4 << endl; 全局的
// friend ostream& operator<<(ostream &out, MyString &obj);
inline ostream &operator<<(ostream &out, const MyString &obj) {
    return out << obj.m_data << endl;   // 若是是*obj.m_data則是 第一個元素
}

inline istream &operator>>(istream &in, MyString &obj) {
    return in >> obj.m_data;
}
MyString.cpp
相關文章
相關標籤/搜索