【C++指南】一文總結C++類和對象【中】

🌟?各位看官好,我是egoist2023

🌍?種一棵樹最好是十年前,其次是現在!

🚀?今天來學習C++類和對象的語法知識。注意:在本章節中,小編會以Date類舉例

👍?如果覺得這篇文章有幫助,歡迎您一鍵三連,分享給更多人哦

目錄

引入

運算符重載

賦值運算符重載

日期類實現

?日期計算

?日期判斷

流插入<<? 和? 流提取>>

const成員函數和取地址運算符重載


引入

//C++中
Date d1(2024, 12, 24);
Date d2(2024, 12, 24);
d1 = d2;//C語言中
d1._year = d2._year;
d1._month = d2._month;
d1._day = d2_day;

在上面一段代碼中,我們想把類類型的d2賦值給d1,如果在C語言版本中是需要把一個一個內置類型拷貝過去,未免過于麻煩。有什么方法能直接讓類對象d2賦值給d1呢?在C++中提出了運算符重載的概念可以為類類型的對象指定新的含義。

運算符重載

  • C++規定類類型對象使用運算符時,必須調用對應運算符重載,若沒有對應的運算符重載,則會編譯報錯
  • 運算符重載是一個函數,具有其返回類型和參數列表以及函數體,由operator和運算符共同構成
//在成員函數中
bool operator=(const Date* d)
    • 幾元運算符對應有幾個運算對象數量。如,一元運算符有一個運算對象,二元運算符有兩個運算對象,且規定二元運算符左側運算對象傳給第一個參數,右側傳給第二個參數。(如果沒有類類型形參則會報錯,在全局函數中 int operator+(int x, int y) )
    • 重載<<和>>時,需要重載為全局函數(把ostream/istream放到第一個形參位置,第二個跟類類型對象)。? 因為重載為成員函數,this指針默認為第一個形參位置,是左側運算對象,調用時就變成了對象<<cout,用起來不習慣。
    ostream& operator<<(ostream& out, const Date& d);
    istream& operator>>(istream& in, Date& d);
    • 運算符重載不能連接語法中沒有的符號,如operator@。 同時注意?.*? ?::? ?sizeof? ??:? . 以上5個運算符不能重載。
    • 一個類是否需要重載哪些運算符,是看重載后是否有意義,比如Date類重載operator-就有意義(可以算差值多少天)。
    • 在C語言中有前置++和后置++,運算符重載函數名都是operator++,為了方便區分。C++規定,后置++重載時,增加?個int形參,跟前置++構成函數重載,方便區分。
    	Date& operator++();//前置++Date operator++(int);//后置++

    賦值運算符重載

    如下一行代碼是否是賦值運算符重載呢?并不是,是拷貝構造。

    注意:拷貝構造是把一個已存在的對象拷貝初始化零一個要創建的對象;

    而賦值運算符重載是?于完成兩個已經存在的對象直接的拷貝賦值。

    Date d1=d2//d1和d2都是類類型對象
    1. 賦值運算符重載 (跟拷貝構造類似)是?個運算符重載,必須重載為成員函數。賦值運算重載的參數建議 寫成const 當前類類型引用 (減少拷貝)。
    返回值時也建議攜程類類型引用(提高效率,支持返回值可提供連續賦值場景)。
    	Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}
    2.沒有顯式實現時,編譯器會默認生成,對內置類型成員變量會淺拷貝(像Date類就可以不實現賦值賦值重載函數),對自定義類型成員變量會調用賦值重載函數(如 Stack ,_a指向了資源,默認生成的賦值重載函數不符合需求,需要 自己實現深拷貝 也對指向的資源也進行拷貝)。
    3.同樣,對于MyQueue這樣的類型內部主要是自定義Stack成員,編譯器默認生成賦值運算符重載會調用Stack的賦值運算符重載。

    日期類實現

    構造函數Date(int year = 1, int month = 1, int day = 1)
    獲取日期int GetMonthDay(int year, int month) const
    日期是否合法bool checkDate() const
    打印日期void Print()

    日期類構造函數不過多介紹。實現代碼如下代碼所示

    //構造函數
    Date::Date(int year, int month, int day)
    {_year = year;_month = month;_day = day;if (!checkDate()){cout << "日期非法:<" << *this << endl;}
    }

    已知某年某月,如何知道是何日呢? 由于該函數需要頻繁調用,故設在類里面,類里默認為inline。

    	int GetMonthDay(int year, int month) const{static int MonthDayArray[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)){return 29;}return MonthDayArray[month];}

    如果輸入的年月日?不符合實際上的年月日,需要一個函數檢查是否合法。

    bool Date::checkDate() const
    {//非法返回falseif (_month < 1 || _month>12 || _day > GetMonthDay(_year, _month) || _day < 1)return false;elsereturn true;
    }
    ?日期計算
    日期+天數

    ?? ?Date operator+(int day) const

    日期+=天數

    ?Date& operator+=(int day)

    日期-天數?? ?Date& operator-=(int day)
    日期-=天數?? ?Date operator-(int day) const
    日期-日期?? ?int operator-(const Date& d) const
    前置/后置++?? ?Date& operator++()? ?前置++
    ?? ?Date operator++(int)? 后置++
    前置/后置--?? ?Date& operator--()? ? ?前置--
    ?? ?Date operator--(int)? ? 后置--

    ?

    ?那是第一種復用第二種,還是第二種復用第一種呢?我們來剖析下函數的具體行為是什么。

    第一種采用的是傳值返回,為什么不傳引用返回呢?因為返回的是tmp,tmp是建立在這個棧空間的,函數結束后棧會被銷毀,因此要用傳值返回。而C++規定類傳值返回會調用拷貝構造,會有一定的消耗。

    第二種采用的是傳引用返回,由于類類型d并不是在此棧空間的,傳引用返回能減少拷貝,提高效率

    可以發現下圖中第二種復用第一種會有5次消耗,而第一種復用第二種只存在2次消耗。

    ?


    同樣日期-天數和日期-=天數也可以采用復用的邏輯。但其中還有借月的邏輯,需要細細來剖析。?

    Date& Date::operator-=(int day)
    {if (day < 0){*this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
    }//優化
    Date Date::operator-(int day) const
    {Date tmp(*this);tmp -= day;return tmp;
    }

    由于實現了日期加減天數的函數,前置和后置的加減都可以采用復用的邏輯。?(這里就不過多贅述)

    //++d
    Date& Date::operator++()
    {//復用*this += 1;return *this;
    }//d++
    Date Date::operator++(int)
    {Date tmp(*this);*this += 1;return tmp;
    }//--d
    Date& Date::operator--()
    {*this -= 1;return *this;
    }//d--
    Date Date::operator--(int)
    {Date tmp(*this);*this -= 1;return tmp;
    }

    接下來我們來看看日期-日期的實現方法。

    當然,也可以通過一個變量來記錄2024年4月5日到2025年3月7日的天數,同樣采用復用的邏輯。

    int Date::operator-(const Date& d) const
    {int flag = 1;Date max = *this;Date min = d;if (*this < d){max = d;min = *this;flag = -1;}int count = 0;while (min != max){++min;++count;}return flag * count;
    }
    ?日期判斷
    日期比較
    d1>d2bool operator>(const Date& d) const
    d1>=d2bool operator>=(const Date& d) const
    d1<d2bool operator<(const Date& d) const
    d1<=d2bool operator<=(const Date& d) const
    d1==d2bool operator==(const Date& d) const
    d1!=d2bool operator!=(const Date& d) const
    bool Date::operator>(const Date& d) const
    {if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month){return _day > d._day;}return true;
    }bool Date::operator==(const Date& d) const
    {return _year == d._year&& _month == d._month&& _day == d._day;
    }

    在實現日期判斷的時候,通常只要實現兩個一個>和==的函數,其他判斷只要復用這兩個函數就可以實現。如要實現d1>=d2,則只要滿足d1>d2或d1==d2;實現d1<d2,則滿足!(d1>=d2)。

    流插入<<? 和? 流提取>>
    流插入<<ostream& operator<<(ostream& out, const Date& d)
    流提取>>istream& operator>>(istream& in, Date& d)

    ?前面我們說過需要把? 流插入<<? 和? 流提取>> 設置為全局變量,否則不符合我們的使用習慣。

    需要注意的是,流插入時類類型d是可以+const,并不改變里面的值,而流提取不可以。

    如果我們輸入的年月日是存在非法的情況的,因此需要判斷。

    //流插入
    ostream& operator<<(ostream& out, const Date& d)
    {out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
    }//流提取
    istream& operator>>(istream& in, Date& d)
    {//in >> d._year >> d._month >> d._day;while (1){in >> d._year >> d._month >> d._day;if (d.checkDate()){break;}else {cout << "輸入日期非法,請重新輸入:<" << endl;}}return in;
    }

    const成員函數和取地址運算符重載

    ?const修飾的成員函數稱之為const成員函數,放到成員函數參數列表的后面。
    void Print() const;
    const修飾的是成員函數隱含的this指針,表明在成員函數中不能對類的任何成員進行修改。
    Date* const this 加const修飾 const Date* const this
    取地址運算符重載分為普通取地址運算符重載和const取地址運算符重載,一般不需要去顯式實現,使用一些特殊情景。如不想讓別人取到當前類對象的地址,就可以自己實現,胡亂返回一個地址,調試的時候就會發現地址一直對不上。
    	Date* operator&(){//return this;return (Date*)0x0123753f;}const Date* operator&() const{//return this;return nullptr;}

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/diannao/72958.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/diannao/72958.shtml
    英文地址,請注明出處:http://en.pswp.cn/diannao/72958.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    PgSql 操作技巧

    1、查詢數據導出csv數據 \COPY (SELECT w.* from t_sys_warn w ) TO /home/cuadmin/warn_output.csv WITH CSV HEADER;2、導出sql Insert語句 pg_dump -U 用戶名 -h 主機名 -p 端口號 -d 數據庫名 --inserts -t 表名 > 導出文件.sqlpg_dump -U username -d dbname -t tabl…

    Unity ES3保存類的問題

    有以下一個物品類 public class Item_Base//基礎物品 { public string ID; private Attribute_Data Item_attribute new(); } 當使用ES3保存這個類時&#xff0c;Item_attribute的數據不會被保存&#xff0c;因為它是私有private ES3保存類時&#xff0c;只會保存…

    react基本功

    useLayoutEffect useLayoutEffect 用于在瀏覽器重新繪制屏幕之前同步執行代碼。它與 useEffect 相同,但執行時機不同。 主要特點 執行時機:useLayoutEffect 在 DOM 更新完成后同步執行,但在瀏覽器繪制之前。這使得它可以在瀏覽器渲染之前讀取和修改 DOM,避免視覺上的閃爍…

    Spring Boot筆記(上)

    01 概要 Spring Boot 是 Java 領域最流行的 快速開發框架&#xff0c;專為簡化 Spring 應用的初始搭建和開發而設計。 一、Spring Boot 解決了什么問題&#xff1f; 傳統 Spring 痛點 ? 繁瑣的 XML 配置 ? 需要手動管理依賴版本 ? 部署依賴外部 Web 服務器&#xff08;如 …

    目標檢測YOLO實戰應用案例100講-基于毫米波雷達的多目標檢測 (續)

    目錄 3.2 改進的CFAR目標檢測算法 3.3 算法步驟描述 3.4 實驗結果與分析 基于VGG16-Net的毫米波雷達目標檢測算法 4.1 VGG16-Net網絡模型 4.2 改進VGG16-Net網絡的目標檢測算法 4.3 算法步驟描述 4.4 實驗結果與分析 知識拓展 基于毫米波雷達的多目標檢測:使…

    gitsubtree怎么添加新的子倉庫

    要使用 git subtree 添加一個新的子倉庫&#xff0c;可以按照以下步驟操作&#xff1a; 1. 添加子倉庫 使用 git subtree add 命令將子倉庫的內容添加到主倉庫的指定目錄中。命令格式如下&#xff1a; git subtree add --prefix<子目錄路徑> <子倉庫地址> <子…

    文本轉語音-音畫適時推送rtsp并播放

    文本語音 rtsp適時播放叫號系統的底層邏輯 發布Linux, unix socket 和window win32做為音頻源的 python10下的(ffmpeg version 7.1) 可運行版本. 這兩天在弄這個&#xff0c;前2篇是通過虛擬聲卡&#xff0c;達到了最簡單的一個邏輯&#xff0c;播放文本就從聲卡發聲&#xff0…

    從0開始的操作系統手搓教程33:掛載我們的文件系統

    目錄 代碼實現 添加到初始化上 上電看現象 掛載分區可能是一些朋友不理解的——實際上掛載就是將我們的文件系統封裝好了的設備&#xff08;硬盤啊&#xff0c;SD卡啊&#xff0c;U盤啊等等&#xff09;&#xff0c;掛到我們的默認分區路徑下。這樣我們就能訪問到了&#xff…

    【圖片批量轉換合并PDF】多個文件夾的圖片以文件夾為單位批量合并成一個PDF,基于wpf的實現方案

    項目背景: 多個圖片分布在不同文件夾,如何以文件夾為單位批量合并成一個PDF,還要保證文件夾里面圖片大小和順序 實現功能: 1、單張圖片的轉換PDF:一張圖臨時轉一下 2、多張圖片轉換成PDF:多張圖單獨轉成PDF 3、多級目錄多張圖轉換成PDF:多級目錄多張圖單獨轉成多個PDF…

    如何用Kimi生成PPT?秒出PPT更高效!

    做PPT是不是總是讓你頭疼&#xff1f;&#x1f629; 快速制作出專業的PPT&#xff0c;今天我們要推薦兩款超級好用的AI工具——Kimi 和 秒出PPT&#xff01;我們來看看哪一款更適合你吧&#xff01;&#x1f680; &#x1f947; Kimi&#xff1a;讓PPT制作更輕松 Kimi的生成效…

    從 MongoDB 到 TDengine,沃太能源實現 18 倍寫入性能提升

    導讀 沃太能源是國內領先儲能設備生產廠商&#xff0c;數十萬儲能終端遍布世界各地。此前使用 MongoDB 存儲時序數據&#xff0c;但隨著設備測點增加&#xff0c;MongoDB 在存儲效率、寫入性能、查詢性能等方面暴露出短板。經過對比&#xff0c;沃太能源選擇了專業時序數據庫 …

    數據庫基本建表操作

    1.登錄數據庫并創建數據庫db_ck 創建完成后使用到我們創建的數據庫。 2.創建表t_hero 根據hero屬性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; 創建完…

    OkHttp 之任務調度模塊源碼分析

    一、引言 在現代網絡應用開發中&#xff0c;高效的任務調度機制對于提升系統性能和用戶體驗至關重要。OkHttp 作為一款廣泛使用的高性能 HTTP 客戶端庫&#xff0c;其任務調度模塊在處理網絡請求的并發、排隊和執行等方面發揮著關鍵作用。本文將深入 OkHttp 源碼&#xff0c;詳…

    復現無人機的項目,項目名稱為Evidential Detection and Tracking Collaboration

    項目名稱為Evidential Detection and Tracking Collaboration&#xff0c;主要用于強大的反無人機系統&#xff0c;涉及新問題、基準和算法研究。下面介紹項目的復現步驟&#xff1a; 安裝環境&#xff1a;使用Anaconda創建并激活名為edtc的虛擬環境&#xff0c;Python版本為3…

    QwQ-32B 開源!本地部署+微調教程來了

    今天&#xff0c;通義千問開源了推理模型QwQ-32B QwQ-32B 在一系列基準測試中進行了評估&#xff0c;測試了數學推理、編程能力和通用能力。以下結果展示了 QwQ-32B 與其他領先模型的性能對比&#xff0c;包括 DeepSeek-R1-Distilled-Qwen-32B、DeepSeek-R1-Distilled-Llama-7…

    如何利用 Excel 表格實現精準文件批量重命名教程

    在處理大量文件時&#xff0c;有時需要根據特定規則對文件名進行調整。如果您的文件名和新名稱之間存在一對多的關系&#xff0c;并且這種關系可以通過 Excel 表格來管理&#xff0c;那么使用“簡鹿文件批量重命名”軟件中的“匹配對應名稱命名”功能將是一個高效的選擇。接下來…

    開關模式電源轉換器 EMI/EMC 的集成仿真

    介紹 在電力電子領域&#xff0c;電磁干擾 &#xff08;EMI&#xff09; 和電磁兼容性 &#xff08;EMC&#xff09; 問題可以決定設計的成敗。開關模式電源轉換器雖然高效且緊湊&#xff0c;但卻是電磁噪聲的常見來源&#xff0c;可能會對附近的組件和系統造成嚴重破壞。隨著…

    Android 藍牙工具類封裝:支持經典藍牙與 BLE,兼容高版本權限

    為了優化經典藍牙&#xff08;Classic Bluetooth&#xff09;和低功耗藍牙&#xff08;Bluetooth Low Energy, BLE&#xff09;的操作&#xff0c;我們可以將功能封裝到一個工具類中&#xff0c;支持掃描、連接、通信&#xff0c;并兼容高版本 Android 的動態權限申請。以下是完…

    STM32 CAN模塊原理與應用詳解

    目錄 概述 一、CAN模塊核心原理 1. CAN協議基礎 2. STM32 CAN控制器結構 3. 波特率配置 二、CAN模塊配置步驟&#xff08;基于HAL庫&#xff09; 1. 初始化CAN外設 2. 配置過濾器 3. 啟動CAN通信 三、數據收發實現 1. 發送數據幀 2. 接收數據幀&#xff08;中斷方式…

    PostgreSQL_安裝部署

    一、Windows系統下安裝 1.下載安裝包 登錄PostgreSQL: Downloads官網&#xff1a; 選擇14.12版本&#xff0c;點擊下載&#xff1a; 2.安裝PostgrSQL14.12 雙擊exe安裝包程序&#xff0c;準備安裝&#xff1a; 選擇安裝路徑&#xff1a; 選擇想安裝的工具&#xff1a; 選擇數…