運算符重載

来源:http://www.cnblogs.com/xiaojiang1025/archive/2016/09/30/5923636.html
-Advertisement-
Play Games

不是所有的運算符都能重載, 以下的都不行 作用域運算符號 成員訪問運算符 成員指針解引用 求類型或者對象大小的運算符 三目運算符 類型信息運算符 寫重載時註意: 不要發明運算符重載,只能對已經有的運算符重載,不能發明運算符 不能對基本類型的運算符的進行重載= 運算符重載中至少有一個類型是類類型 不能 ...


不是所有的運算符都能重載, 以下的都不行
:: 作用域運算符號
. 成員訪問運算符
.* 成員指針解引用
sizeof 求類型或者對象大小的運算符
?: 三目運算符
typei類型信息運算符
寫重載時註意:

  • 不要發明運算符重載,只能對已經有的運算符重載,不能發明運算符
  • 不能對基本類型的運算符的進行重載=>運算符重載中至少有一個類型是類類型
  • 不能改變運算符的運算特性和優先順序,比如把二元運算符改成一元的
  • 只能重載成成員的運算符:=+= ,-=, *=, /=, %=,[] 下標取值,() 圓括弧運算符,-> 指針運算符,* 指針解引用運算符
  • 只能重載成全局函數的運算符:>>, <<
  • 如果不給一個類型提供賦值運算符,則編譯器會體統一個預設的賦值運算符,這個運算符完成的是逐位元組拷貝,這樣會產生多個指針指向同一塊記憶體,並且可能產生記憶體泄露。類似預設的拷貝構造

+,*,*=重載

clasFraction{
    inx;
    iny;
    public:
        Fraction(inx=int y=1):x(x),y(y){}
        voishow(){
            cout<<x<<'/'<<y<<endl;
        }
        //成員形式的運算符重載,this充當第一個參數,且可以省略
        Fractiooperator+(const Fraction& fb)const{  //有這個的話不能和全局的區分,只留一個就行,
            returFraction(x*fb.y+y*fb.x,y*fb.y);
        }
        Fractiooperator*(const Fraction& fb)const{
            returFraction(x*fb.x,y*fb.y);
        }
        Fractiooperator*=(const Fraction& fb){      //當前對象要變,不能加const
            x*=fb.x;
            y*=fb.y;
            retur*this;
        }
};
//全局形式
Fractiooperator+(const Fraction& fa,const Fraction& fb){
    returFraction(fa.x*fb.y+fa.y*fb.x,fa.y*fb.y);
}

clasInteger{
    indata;
    public:
        Integer(indata=:data(data){ //後半部分才是真正的構造
        }
        voishow(){
            cout<<data<<endl;
        }
        /*
        //使用成員函數實現operator+
        Integeoperator+(const Integer& i)const{
        //  returInteger(data+i.data);  //匿名對象
            returdata+i.data;           //單參構造
        }
        */
        stativoid showData(Integer* mythis){        //static函數使用普通變數要this
            cout<<mythis->data<<endl;
        }
    private:
        //聲明友元
        frienconst Integer operator+(const Integer& ia,const Integer& ib);
};
//使用全局函數實現operator+
consInteger operator+(const Integer& ia,const Integer& ib){
    //正常情況下許可權有問題,可以定義一個getData()函數或用友元解決
    //開頭的const是為了保證返回的臨時結果不可以被覆蓋
    returInteger(ia.data+ib.data);  
}

cout/cin重載

cout是ostream& 流類型不能複製,必須用引用類型,也不能const修飾,cin同理,編譯器會先去ostream類型(L對象)中找一個成員函數operator<<(const Integer&),如果找不到就去全局找一個全局函數operator<<(ostream& ps,const Interger& i)

#include<iostream>
usinnamespace std;
clasInteger{
    indata;
    public:
        Integer(indata=:data(data){     //後半部分的初始化列表的部分才是真正的構造
        }
        frienostream& operator<<(ostream& os,const Integer& i);
        frienistream& operator>>(istream& is,Integer& i);
        //成員形式的operator==
        boooperator==(const Integer& i){
            returdata==i.data;  //返回指針的話this==&i(極少用)
        }
};
//全局形式的輸出運算符重載
ostreamoperator<<(ostream& os,const Integer& i){
    returos<<i.data;
}
//全局形式的輸入運算符重載
istreamoperator>>(istream& is,Integer& i){
    returis>>i.data;
}
inmain(){
    Integeia(,ib(0);
    if(ia==ib){
        cin>>ia;
        cout<<ia<<endl;
    }
    retur
}

二元運算符L#R的重載中編譯器會先去L對象對應的類型中找一個重載函數叫operator#(R),沒有就去全局函數中找一個全局函數叫operator#(L,R),最後綜合選擇最優調用

一元運算符重載

先去O對象對應的類型找一個成員函數叫operator#(), 如果找不到就去全局找一個全局函數operator#(O),#預設操作符號在前,操作數在後

clasInteger{
    indata;
    public:
        Integer(indata=:data(data){ //後半部分才是真正的構造
        }
        frienostream& operator<<(ostream& os,const Integer& i);
        frienistream& operator>>(istream& is,Integer& i);
        boooperator!(){
            retur!data;
        }
        Integeoperator-(){
            retur-data;
        }
        Integeroperator--(){        //前--
            data--;
            retur*this;
        }
        consInteger operator--(int){    //後--
            /*
            Integetmp=*this;
            data--;
            returtmp;
            */
            returdata--;    //返回的是變化之前的結果
        }
        Integeroperator++(){        //前++
            data++;
            retur*this;
        }
        consInteger operator++(int){    //後++
            returdata++;
        }
};
//全局形式的輸出運算符重載
ostreamoperator<<(ostream& os,const Integer& i){
    returos<<i.data;
}
//全局形式的輸入運算符重載
istreamoperator>>(istream& is,Integer& i){
    returis>>i.data;
}
inmain(){
    Integeia(,ib();
    cout<<!ia<<endl;
    cout<<!ib<<endl;
    cout<<-ia<<endl;
    cout<<-ia<<endl;        //註意是兩個-,不是--
    cout<<-(-ia)<<endl;
    cout<<--ia<<endl;
    cout<<ia--<<endl;
    cout<<ia<<endl;
    cout<<++ia<<endl;
    cout<<ia++<<endl;
    cout<<ia<<endl;
    cout<<-ib<<endl;
}

new/delete運算符重載

clasA{
    inx;
    iny;
    public:
        A(){cout<<"A()"<<endl;}
        ~A(){cout<<"~A()"<<endl;}
};
stativoid* operator new(size_t size){   //new運算符全局的成員的都一個樣
    cout<<"size="<<size<<endl;
    returmalloc(size);
}
stativoid operator delete(void* ptr){
    cout<<"ptr="<<ptr<<endl;
}
inmain(){
    Apa=new A();
    deletpa;
    retur
}
strin對象的使用:
inmain(){
    strinstra("hello");
    strinstrb="hello";
    strb="world";
    if(stra==strb)
        cout<<"stra==strb"<<endl;
    else
        cout<<"stra!=strb"<<endl;
    cout<<strb<<endl;
    cout<<(strb.append(test"))<<endl;
    cout<<(stra+=test")<<endl;
    cout<<(stra=stra+strb)<<endl;
    cout<<stra.size()<<endl;
    cout<<stra[4]<<endl;
    cout<<stra.at(4)<<endl;
    //把C++ string 變成const char*
    const char* mystr=stra.c_str();
    cout<<mystr<<endl;
    cout<<strlen(mystr)<<endl;
}

()的重載

#include<iostream>
using namespace std;
class Product{
    //產品數量
    int pcount;
    //產品單價
    double price;
    public:
        Product(int pcount=0,double price=0.0):pcount(pcount),price(price){}
        //重載()運算符
        double operator()(int c,double p){
            return c*p;
        }
        double operator()(int c,double p,double pct){
            return c*p*pct;
        }
        //重載()運算符,把當前對象類型變成int
        //int operator() (){    //Wrong! 
        operator int(){ //
            return pcount;
        }
        //把當前對象類型轉換成double
        operator double(){
            return price;
        }
};
int main(){
    Product iphone;
    double sumprice=iphone(9,.6);   //對象已經創建了,這裡的()可不是初始化
    cout<<sumprice<<endl;
    cout<<iphone(9,.6,0.8)<<endl;
    Product iphone6s(99,.4);
    int c=(int)iphone6s;
    cout<<c<<endl;
    double p=(double)iphone6s;
    cout<<p<<endl;
    return 0;
}

例子

#include<iostream>
using namespace std;
class Array{
    //數組容量
    int len;
    //元素的個數
    int size;
    //真正存儲數據的指針
    int* data;
    public:
        //構造
        expliciArray(int len=:len(len),size(0){ 
        //size一定要初始化為否則容易越界
            //申請堆記憶體
            data=neint[len];
        }
        //析構    
        ~Array(){
            //釋放堆記憶體
            delete[data;
        }
        //拷貝構造
        Array(consArray& arr){
            //淺拷貝
            len=arr.len;
            size=arr.size;
            //深拷貝,重新申請堆記憶體
            data=neint[len];
            //複製數據
            for(ini=i<size;i++)
                data[i]=arr.data[i];
        }
        //添加數據
        voipush_back(int d){
            if(size>=len)
                expand();
            data[size++]=d;
        }
        //擴容
        voiexpand(){
            len=len+1;
            //記錄原來的記憶體
            in*tmp=data;
            //重新申請堆記憶體
            data=neint[len];
            //複製數據
            for(ini=i<size;i++)
                data[i]=tmp[i];
            //釋放原來的記憶體
            delete[tmp;
        }
        //顯示數據
        //其實是全局函數寫在了類內,輸入輸出重載不能在類內
        friend ostream& operator<<(ostream& os,const Array& arr){
            cout<<'[';
            for(ini=i<arr.size;i++)
                cout<<arr.data[i]<<' ';
            cout<<"]";
        }
        //賦值運算符重載
        Arrayoperator=(const Array& arr){
            //防止自賦值
            if(this!=&arr){
                len=arr.len;
                size=arr.size;
                //釋放原來的記憶體,防止原來的空間不夠大
                delete[data;
                //重新申請記憶體
                data=neint[len];
                //複製數據
                for(ini=i<size;i++){
                    data[i]=arr.data[i];
                }
            }
            retur*this;
 
        }
        //[]運算符的重載
        intoperator[](const unsigned int i){//operator[]不能有預設值,因為有了預設值作為二元運算符的[]就變成了單目運算符
            retur*(data+i);
        }
 };
 voifoo(){
    Arraarra(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    Arraarrb;
    arrb=arra;
    cout<<arrb[<<endl;
    cout<<arrb<<endl;
 }
 inmain(){
    foo();
    retur
 }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在項目中Maven用的一直比較多,以前只知道簡單的配置一些依賴,所以找了時間 孔浩老師 Maven的學習視頻學習了一下 Maven初步 手動建立 Maven 項目 1、新建一個簡單 項目 手動 項目:按照 規範建立項目路徑和 2、常用的Maven 命令 3、maven 預設的中央倉庫的地址 在 中 ...
  • HTML: HTML的概述及作用: HTML全稱為HyperText Markup Language,譯為超文本標記語言,不是一種編程語言,是一種描述性的標記語言,用於描述超文本中內容的顯示方式。比如字體什麼顏色,大小等。 Html就是超文本標記語言的簡寫,是最基礎的網頁語言。 Html是通過標簽來 ...
  • 策略模式屬於對象的行為模式。其用意是針對一組演算法,將每一個演算法封裝到具有共同介面的獨立的類中,從而使得它們可以相互替換。策略模式使得演算法可以在不影響到客戶端的情況下發生變化。 本文地址:http://www.cnblogs.com/wuyudong/p/5924223.html,轉載請註明源地址。 ...
  • python2.x中處理中文,是一件頭疼的事情。網上寫這方面的文章,測次不齊,而且都會有點錯誤,所以在這裡打算自己總結一篇文章。 我也會在以後學習中,不斷的修改此篇博客。 這裡假設讀者已有與編碼相關的基礎知識,本文不再再次介紹,包括什麼是utf-8,什麼是unicode,它們之間有什麼關係。str與 ...
  • 最近在做一個新的項目,從RDS備份到OSS,進行數據備份以及後續的還原。這邊對阿裡雲的OSS數據上傳介面進行說明,先做下筆記先簡單介紹下OSS: ①Object 在OSS中,用戶操作的基本數據單元是Object。單個Object最大允許存儲5TB的數據。Object包含key、meta和data。其 ...
  • 字元串輸入 Python用到的輸入一般有兩種方式, 和 ,區別是,前者只能輸入數字,後者輸入的是字元串,使用如下: 字元串輸出 輸出使用 即可,後邊可加變數,也可以直接用"、'和'''來包含字元串,使用示例如下: 正常情況下均可以使用,可以使用一種包含一個字元串,字元串中可以包含另外一種(但是不可以 ...
  • 下載: 1.在spring-mvc中配置(用於100M以下的文件下載) <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messa ...
  • Thread提供了stop()方法終止線程,但是該方法是強行終止,容易產生一些錯誤,已經被廢棄。 可以使用退出標誌來終止線程,在run()函數裡面設置while迴圈,把退出標誌作為while的條件,當條件為false時,run函數執行完畢,線程就自動終止了。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...