天天看點

【c++】重載操作符

目錄

  1. 輸入和輸出操作符
  2. 算術操作符和關系操作符
  3. 下标操作符
  4. 自加、自減操作符
  5. 成員通路操作符

1  輸入和輸出操作符

1.1 輸出操作符

1.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {} //構造函數帶預設參數
    private:
        int val;
        stringostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    cout << b << endl;
}      

結果

【c++】重載操作符

1.1.2 說明

1)IO操作必須為非成員函數

原因:I/O操作的接口傳回的是ostream&對象(隻有傳回左值,這樣才可以連續的輸出,例如cout << a << b)。自定義的輸出操作符應該與其相似。如果将其定義為成員函數(有個首預設參數this,即指向自己的指針),左操作數隻能是該類型的對象,則沒法辦到。例如:Sales_item; item << cout; 與正常定義相反,是以隻能為非成員函數。

2)因為要通路指定類的私有成員,是以在該類中聲明輸出操作符為友員函數。

3)第一個形參必須為引用。因為I/O對象不可以複制。同理傳回值必須為一個引用。

4)第一個形參不可以為const,因為寫入到流會改變其值。

5)第二個為引用,這樣可以避免複制。參數可以為const,可以接收const對象和非const對象;否則,如果為非const,則隻能接收非coust對象。一般為const,畢竟隻是輸出而已,不改變對象。

1.2 輸入操作符

1.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend istream& operator>>(istream& in, A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {}
    private:
        int val;
        string ss;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}
istream& operator>>(istream& in, A& a)
{
    in >> a.ss >> a.val;
    if(in)
    {
        cout << "Input right" << endl;
    }
    else
    {
        cout << "in.fail:" << in.fail() << endl;
        cout << "input wrong!" << endl;
    }
    return in; 
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    cin >> b;
    cout << b << endl;
}      

結果

【c++】重載操作符

1.2.2 說明

1)輸入與輸出操作符的重要差別:輸入操作符必須處理錯誤和檔案結束的可能性。

2)輸入如果有多個值的話,如果一個數錯了,整個輸入對象就錯了(False),從示例中可以看出,前邊指派正确的已經生效了,後邊的用了預設值,可以這樣設計:如果輸入錯誤,将整個對象複位,恢複到最初的狀态,例:

【c++】重載操作符
【c++】重載操作符
#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend istream& operator>>(istream& in, A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {}
        A(const A& a)
        {
            ss = a.ss;
            val = a.val;
        } 

        A& operator=(const A& a) 
        {
            if(this != &a)
            {
                ss = a.ss;
                val = a.val;
                return *this;
            }
        }
    private:
        int val;
        string ss;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}
istream& operator>>(istream& in, A& a)
{
    in >> a.ss >> a.val;
    if(in)
    {
        cout << "Input right" << endl;
    }
    else
    {
        cout << "in.fail:" << in.fail() << endl;
        cout << "input wrong!" << endl;
        a = A();
    }
    return in; 
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    b = a;
    cin >> b;
    cout << b << endl;
}      

View Code

2 算術操作符和關系操作符

2.1 相等操作符

2.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend bool operator==(const A& a, const A& b);
    friend bool operator!=(const A& a, const A& b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
    private:
        string ss;
        int val;
};

bool operator==(const A& a, const A& b)
{
    return a.ss == b.ss && a.val == b.val;
}

bool operator!=(const A& a, const A& b)
{
    return !(a == b);
}

int main()
{
    A a("hello", 53);
    A b("hello", 54);
    A c("hello", 54);
    cout << "a == b?:" << (a == b) << endl;
    cout << "a != b?:" << (a != b) << endl;
    cout << "b == c?:" << (b == c) << endl;
    cout << "b != c?:" << (b != c) << endl;
}      

結果

【c++】重載操作符

2.1.2說明

1)定義了類的==,對應的應該定義!=

2.2 關系操作符

2.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend bool operator<(const A& a, const A& b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
    private:
        string ss;
        int val;
};

bool operator<(const A& a, const A& b)
{
    return (a.val < b.val);
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    cout << "a < b?:" << (a < b) << endl;
}      

結果

【c++】重載操作符

2.2.2 說明

1)定義了相等操作符,一般也定義關系操作符

2)關系操作符要根據具體的含義定義

2.3 指派操作符

2.3.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator=(const A& a);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A& A::operator=(const A& a)
{
    if(this != &a)
    {
        ss = a.ss;
        val = a.val;
    }
    return *this;
}


int main()
{
    A a("hello", 53);
    A b("he", 55);
    cout << b << endl;
    b = a;
    cout << b << endl;
}      

2.3.2 說明

1) 複制操作符完成對同類對象的指派,參數一般為對類類型的const引用。

2)如果沒有,編譯器會自動合成一個,類的指派操作符一定為類的成員變量,以便編譯器是否需要自己合成一個。

3)傳回值必須為*this的引用,這樣就不需要建立和撤銷結果的臨時副本。同理的有複合指派操作符,例如

【c++】重載操作符
【c++】重載操作符
#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator+=(const A &);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A& A::operator+=(const A& a)
{
    val += a.val;
    return *this;
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    a += b;
    cout << a << endl;
}      

View Code

結果

【c++】重載操作符

2.4 加法操作符

2.4.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend A operator+(const A &a ,const A &b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A(const A&);
        A& operator+=(const A &);
    private:
        string ss;
        int val;
};

A::A(const A& a) 
{
    ss = a.ss;
    val = a.val;
}

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A operator+(const A &a ,const A &b)
{
    A tmp(a);
    tmp += b;
    return tmp;
}

A& A::operator+=(const A& a)
{
    val += a.val;
    return *this;
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    a += b;
    cout << a + b << endl;
}      

2.4.2 說明

1) 根據複合操作符(如+=)實作算術操作符(如+),比其他方式更有效

3 下标操作符

3.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        char& operator[](const size_t);
        const& char operator[](const size_t) const;
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

char& A::operator[](const size_t index)
{
    return ss[index];
}

const char& A::operator[](const size_t index) const
{
    return ss[index];
}


int main()
{
    A a("hello", 53);
    cout << a[2] << endl;
}      

結果

e

3.1.2 說明

1) 下标操作必須為函數成員,因為傳遞一個參數,還需要另一個指向自己的指針參數,正好函數成員的this可以勝任。

2) 類定義下标時,一般定義兩個版本:一個為非const成員,并傳回非const引用; 另一個為const成員,并傳回const引用。這樣應用與const對象時,傳回值應為const引用,不能用作指派的目标。

4 自加、自減操作符

4.1 前置自加、自減操作符

4.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator++();
        A& operator--();
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

A& A::operator++()
{
    ++val;
    return *this;
}

A& A::operator--()
{
    --val;
    return *this;
}

int main()
{
    A a("hello", 53);
    cout << a << endl;
    ++a;
    cout << a << endl;
    ++a;
    cout << a << endl;
    --a;
    cout << a << endl;
}      

結果

【c++】重載操作符

4.2 後置自加、自減操作符

4.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator++();
        A& operator--();
        A operator++(int);
        A operator--(int);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

A& A::operator++()
{
    ++val;
    return *this;
}

A& A::operator--()
{
    --val;
    return *this;
}
A A::operator++(int)
{
    A tmp(*this);
    ++(*this);
    return tmp;
}

A A::operator--(int)
{
    A tmp(*this);
    --(*this);
    return tmp;
}

int main()
{
    A a("hello", 53);
    cout << a << endl;
    ++a;
    cout << a << endl;
    ++a;
    cout << a << endl;
    cout << "hello" << endl;
    cout << (a--) << endl;;
    cout << a << endl;
}      

4.2.2 說明

1)為了區分與前置自加、自減操作符的差別,後置需要接受一個而外的(無用的)的int型形參。使用字尾式操作符時,編譯器提供0作為這個形參的實參,其唯一目的是為了差別字首、字尾。

2)a++傳回的是加之前的狀态,是以,定義一個局部對象,儲存(*this),最後傳回這個局部變量的備份(注意不可以為引用,畢竟是局部的)。

5. 成員通路操作符

5.1.1 示例

#include <iostream>
#include <string>
using namespace std;
class B
{
    public:
        void print_B() { cout << "hello !!" << endl; }
};
class U_Ptr 
{
    friend class HasPtr;
    B* ip;
    size_t use;
    U_Ptr(B *p) : ip(p), use(1) {}
    ~U_Ptr() { delete ip; }
};

class HasPtr
{
    public:
        HasPtr(B *p, int i) : ptr(new U_Ptr(p)), val(i) {}
        HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) { ++ptr->use; }
        HasPtr& operator=(const HasPtr &orig);
        ~HasPtr() { if(--ptr->use == 0) delete ptr; }
        B& operator*() { return *ptr->ip; }
        B* operator->() { return ptr->ip; }
    private:
        U_Ptr *ptr;
        int val;
};

HasPtr& HasPtr::operator=(const HasPtr &orig)
{
    if(this != &orig)
    {
        ptr = orig.ptr;
        val = orig.val;
        ++(ptr->use);
    }
    return *this;
}

int main()
{
    HasPtr hasptr1(new B, 23);
    HasPtr hasptr2(hasptr1);
    *hasptr1;
    hasptr1->print_B();
}      

結果

hello!!

5.1.2 說明

1) 箭頭必須定義為成員函數, 解引用不要求定義為成員,但是可以作為成員。

2) 解引用和箭頭操作常用在實作智能指針的類中。