深入剖析 C++ 默認函數:拷貝構造與賦值運算符重載

目錄

1. 簡單認識C++ 類的默認函數

1.1 默認構造函數

1.2 析構函數

1.3 拷貝構造函數

2. 拷貝構造函數的深入理解

拷貝構造的特點:?

實際運用

3. 賦值運算符重載的深入理解

3.1.運算符重載

3.2樣例

1.比較運算符重載

2.算術運算符重載

3.自增和自減運算符重載

4.輸入輸出運算符重載

?3.3.賦值運算符重載

總結


在 C++ 編程中,類的默認函數拷貝構造函數以及賦值運算符重載是非常重要的概念。它們不僅可以讓我們更方便地操作對象,還能增強代碼的可讀性和可維護性。本文將結合提供的日期類(Date)代碼,深入剖析這些概念。

1. 簡單認識C++ 類的默認函數

在 C++ 中,當我們定義一個類時,編譯器會自動為我們生成一些默認的成員函數,包括默認構造函數、析構函數、拷貝構造函數和賦值運算符重載函數。不過,當我們手動定義了其中某些函數時,編譯器就不會再生成對應的默認函數了。

1.1 默認構造函數

默認構造函數是在創建對象時沒有提供任何參數時調用的函數。在Date類中,我們手動定義了一個帶參數的構造函數:

Date(int year = 1, int month = 1, int day = 1)
{_year = year;_month = month;_day = day;
}

這個構造函數有默認參數,因此它既可以作為帶參數的構造函數使用,也可以作為默認構造函數使用。當我們創建對象時不提供參數,就會使用默認值year = 1, month = 1, day = 1

1.2 析構函數

析構函數在對象生命周期結束時自動調用,用于釋放對象占用的資源。在Date類中,析構函數如下:

~Date()//可不寫
{_year = 0;_month = 0;_day = 0;
}

1.3 拷貝構造函數

拷貝構造函數用于創建一個新對象,該對象是另一個已存在對象的副本。在Date類中,注釋掉的拷貝構造函數如下:

// Date(const Date& d1)//可不寫
// {
//     _year = d1._year;
//     _month = d1._month;
//     _day = d1._day;
// }

2. 拷貝構造函數的深入理解

如果一個構造函數的第一個參數是自身類類型的引用,且任何額外的參數都有默認值,則此構造函數也叫做拷貝構造函數,也就是說拷貝構造是一個特殊的構造函數。


拷貝構造的特點:?


1.拷貝構造函數是構造函數的一個重載。
2.拷貝構造函數的參數只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為語法邏輯上會引發無窮遞歸調用。
3.C++規定自定義類型對象進行拷貝行為必須調用拷貝構造,所以這里自定義類型傳值傳參和傳值返回都會調用拷貝構造完成。
4.若未顯式定義拷貝構造,編譯器會生成自動生成拷貝構造函數。自動生成的拷貝構造對內置類型成員變量會完成值拷貝/淺拷貝(一個字節一個字節的拷貝),對自定義類型成員變量會調用他的拷貝構造。

?5.像Date這樣的類成員變量全是內置類型且沒有指向什么資源,編譯器自動生成的拷貝構造就可以完成需要的拷貝,所以不需要我們顯示實現拷貝構造。像Stack這樣的類,雖然也都是內置類型,但是_a指向了資源,編譯器自動生成的拷貝構造完成的值拷貝/淺拷貝不符合我們的需求,所以需要我們自己實現深拷貝(對指向的資源也進行拷貝)。像MyQueue這樣的類型內部主要是自定義類型Stack成員,編譯器自動生成的拷貝構造會調用Stack的拷貝構造,也不需要我們顯示實現MyQueue的拷貝構造。這里還有一個小技巧,如果一個類顯示實現了析構并釋放資源,那么他就需要顯示寫拷貝構造,否則就不需要。

實際運用

拷貝構造函數的原型通常為ClassName(const ClassName& other)。當我們使用以下方式創建對象時,會調用拷貝構造函數:

Date d1(2025, 6, 12);
Date d2(d1); // 調用拷貝構造函數

Date類中,由于成員變量都是基本數據類型,淺拷貝就足夠了。但如果類中包含動態分配的資源(如指針),淺拷貝可能會導致多個對象指向同一塊內存,從而在析構時引發重復釋放的問題,這時就需要手動定義拷貝構造函數進行深拷貝。

3. 賦值運算符重載的深入理解

3.1.運算符重載

1.當運算符被用于類類型的對象時,C++語言允許我們通過運算符重載的形式指定新的含義。C++規定類類型對象使用運算符時,必須轉換成調用對應運算符重載,若沒有對應的運算符重載,則會編譯報錯。
2.運算符重載是具有特殊名字的函數,他的名字是由operator和后面要定義的運算符共同構成。和其他函數一樣,它也具有其返回類型和參數列表以及函數體。
3.重載運算符函數的參數個數和該運算符作用的運算對象數量一樣多。一元運算符有一個參數,二元運算符有兩個參數,二元運算符的左側運算對象傳給第一個參數,右側運算對象傳給第二個參數。
4.如果一個重載運算符函數是成員函數,則它的第一個運算對象默認傳給隱式的this指針,因此運算符重載作為成員函數時,參數比運算對象少一個。
5.運算符重載以后,其優先級和結合性與對應的內置類型運算符保持一致。不能通過連接語法中沒有的符號來創建新的操作符:比如operator@。
6.注意以下5個運算符不能重載

7.重載操作符至少有一個類類型參數,不能通過運算符重載改變內置類型對象的含義,如:int
operator+(int x,int y)
8.一個類需要重載哪些運算符,是看哪些運算符重載后有意義,比如Date類重載operator-就有意義,但是重載operator+就沒有意義。

3.2樣例

1.比較運算符重載

比較運算符(==,?!=,?>,?>=,?<,?<=)用于比較兩個對象的大小關系。以==運算符重載為例:

bool Date::operator==(const Date& d) const
{return _year == d._year&& _month == d._month&& _day == d._day;
}

?這個函數比較兩個Date對象的年、月、日是否相等,如果相等則返回true,否則返回false。其他比較運算符的重載也類似,通過比較成員變量的值來確定對象的大小關系。

2.算術運算符重載

算術運算符(+,?-,?+=,?-=)用于對日期進行加減操作。以+=運算符重載為例

Date& Date::operator+=(int day)
{if(day < 0){return *this -= (-day);}_day += day;while(_day > GetMonthDay(_year, _month))//獲取該月天數的函數{_day -= GetMonthDay(_year, _month);++_month;if(_month == 13){_year++;_month = 1;}}return *this;
}

這個函數將日期加上指定的天數,并處理了跨月和跨年的情況。+運算符重載則是通過調用+=運算符重載來實現的:

Date Date::operator+(int day) const
{Date tmp = *this;tmp += day;return tmp;
}
3.自增和自減運算符重載

自增和自減運算符(++,?--)分為前置和后置兩種形式。前置運算符返回引用,后置運算符返回臨時對象。以前置++運算符重載為例:

Date& Date::operator++()
{*this += 1;return *this;
}

后置++運算符重載通過一個int參數來區分前置和后置:

Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}
4.輸入輸出運算符重載

輸入輸出運算符(<<,?>>)用于將對象輸出到流中或從流中讀取對象。

ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}

?這個函數將Date對象的年、月、日輸出到輸出流中。>>運算符重載則用于從輸入流中讀取年、月、日,并檢查輸入的日期是否合法:

istream& operator>>(istream& in, Date& d)
{while(1){cout << "請輸入年月日:>";in >> d._year >> d._month >> d._day;if(!d.CheckDate()){cout << "輸入的日期非法!";d.Print();cout << "請重新輸入年月日!!" << endl;}else{break;}}return in;
}

?3.3.賦值運算符重載

賦值運算符重載是一個默認成員函數,用于完成兩個已經存在的對象直接的拷貝賦值,這里要注意跟拷貝構造區分,拷貝構造用于一個對象拷貝初始化給另一個要創建的對象。

賦值運算符重載的特點:
1.賦值運算符重載是一個運算符重載,規定必須重載為成員函數。賦值運算重載的參數建議寫成const 當前類類型引用,否則會傳值傳參會有拷貝
2.有返回值,且建議寫成當前類類型引用,引用返回可以提高效率,有返回值目的是為了支持連續值場景。
3.沒有顯式實現時,編譯器會自動生成一個默認賦值運算符重載,默認賦值運算符重載行為跟默認構造函數類似,對內置類型成員變量會完成值拷貝/淺拷貝(一個字節一個字節的拷貝),對自定義類型成員變量會調用他的拷貝構造。
4.像Date這樣的類成員變量全是內置類型且沒有指向什么資源,編譯器自動生成的賦值運算符重載可以完成需要的拷貝,所以不需要我們顯示實現賦值運算符重載。像Stack這樣的類,雖然也都是內置類型,但是_a指向了資源,編譯器自動生成的賦值運算符重載完成的值拷貝/淺拷貝不符合我們的需求,所以需要我們自己實現深拷貝(對指向的資源也進行拷貝)。像MyQueue這樣的類型內部主要是自定義類型Stack成員,編譯器自動生成的賦值運算符重載會調用Stack的賦值運算符重載,也不需要我們顯示實現MyQueue的賦值運算符重載。這里還有一個小技巧,如果一個類顯示實現了析構并釋放資源,那么他就需要顯示寫賦值運算符重載,否則就不需要。

總結

通過對Date類的分析,我們深入了解了 C++ 類的默認函數、拷貝構造函數和賦值運算符重載的概念和用法。默認函數為我們提供了基本的對象創建和銷毀機制,拷貝構造函數用于創建對象的副本,運算符重載則讓我們可以像使用內置類型一樣使用自定義類型進行運算。在實際編程中,我們需要根據類的具體情況來決定是否需要手動定義這些函數,以確保代碼的正確性和性能。

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

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

相關文章

板凳-------Mysql cookbook學習 (十--3)

5.16 用短語來進行fulltext查詢 mysql> select count(*) from kjv where match(vtext) against(God); ---------- | count(*) | ---------- | 0 | ---------- 1 row in set (0.00 sec)mysql> select count(*) from kjv where match(vtext) against(sin); -------…

python爬蟲ip封禁應對辦法

目錄 一、背景現象 二、準備工作 三、代碼實現 一、背景現象 最近在做爬蟲項目時&#xff0c;爬取的網站&#xff0c;如果發送請求太頻繁的話&#xff0c;對方網站會先是響應緩慢&#xff0c;最后是封禁一段時間。一直是拒絕連接&#xff0c;導致程序無法正常預期的爬取數據…

【AIGC】Qwen3-Embedding:Embedding與Rerank模型新標桿

Qwen3-Embedding&#xff1a;Embedding與Rerank模型新標桿 一、引言二、技術架構與核心創新1. 模型結構與訓練策略&#xff08;1&#xff09;多階段訓練流程&#xff08;2&#xff09;高效推理設計&#xff08;3&#xff09;多語言與長上下文支持 2. 與經典模型的性能對比 三、…

算法競賽階段二-數據結構(32)數據結構簡單介紹

數據結構的基本概念 數據結構是計算機存儲、組織數據的方式&#xff0c;旨在高效地訪問和修改數據。它是算法設計的基礎&#xff0c;直接影響程序的性能。數據結構可分為線性結構和非線性結構兩大類。 線性數據結構 線性結構中&#xff0c;數據元素按順序排列&#xff0c;每…

Windows桌面圖標修復

新建文本文件&#xff0c;粘入以下代碼&#xff0c;保存為.bat文件&#xff0c;管理員運行這個文件 duecho off taskkill /f /im explorer.exe CD /d %userprofile%\AppData\Local DEL IconCache.db /a start explorer.exe echo 執行完成上面代碼作用是刪除桌面圖標緩存庫&…

13.react與next.js的特性和原理

&#x1f7e1; 一句話總結 React 專注于構建組件&#xff0c;而 Next.js 是基于 React 的全棧框架&#xff0c;提供了頁面路由、服務端渲染和全棧能力&#xff0c;讓你能快速開發現代 Web 應用。 React focuses on building UI components, while Next.js is a full-stack fra…

全棧監控系統架構

全棧監控系統架構 可觀測性從數據層面可分為三類&#xff1a; 指標度量(Metrics)&#xff1a;記錄系統的總體運行狀態。事件日志(Logs)&#xff1a;記錄系統運行期間發生的離散事件。鏈路追蹤(Tracing)&#xff1a;記錄一個請求接入到結束的處理過程&#xff0c;主要用于排查…

云服務運行安全創新標桿:阿里云飛天洛神云網絡子系統“齊天”再次斬獲獎項

引言 為認真落實工信部《工業和信息化部辦公廳關于印發信息通信網絡運行安全管理年實施方案的通知》&#xff0c;2025年5月30日中國信息通信研究院于浙江杭州舉辦了“云服務運行安全高質量發展交流會”&#xff0c;推動正向引導&#xff0c;鞏固云服務安全專項治理成果。會上&a…

刀客doc:WPP走下神壇

一、至暗時刻&#xff1f; 6月11日&#xff0c;快消巨頭瑪氏公司宣布其價值17 億美元&#xff0c;在全球70個市場的廣告業務交給陽獅集團&#xff0c;這其中包括M&Ms、士力架、寶路等知名品牌。 此前&#xff0c;瑪氏公司一直是WPP的大客戶。早在今年3月&#xff0c;WPP就…

進行性核上性麻痹飲食攻略:營養安全雙護航

進行性核上性麻痹是一種罕見的神經系統退行性疾病&#xff0c;主要影響患者的運動、平衡和吞咽功能。除了醫學干預&#xff0c;科學的飲食管理也能在一定程度上減輕癥狀&#xff0c;提高生活質量。 由于患者常出現吞咽困難&#xff0c;食物質地的選擇尤為重要。應避免干硬、大塊…

阿里云可觀測 2025 年 5 月產品動態

本月可觀測熱文回顧 文章一覽&#xff1a; StoreView SQL&#xff0c;讓數據分析不受地域限制 不懂 PromQL&#xff1f;AI 智能體幫你玩轉大規模指標數據分析 DeepWiki LoongCollector&#xff1a;AI 重塑開源代碼理解 從 o11y 2.0 說起&#xff0c;大數據 Pipeline 的「…

React 基礎狀態管理方案

1. useState useState 是 React 提供的最基本的 Hook,用于在函數組件中添加狀態管理。它返回一個狀態變量和一個更新狀態的函數。 1.1. 使用場景 適合管理簡單的狀態。 適合管理組件內部的局部狀態。 1.2. 示例代碼 import React, { useState } from react;function Cou…

VScode中如何創建項目分支

在 VS Code 中為前端項目創建自己的分支是一個常見的開發實踐&#xff0c;以下是詳細步驟&#xff1a; 前提條件 已安裝 Git已安裝 VS Code已有前端項目或克隆了遠程倉庫 創建分支步驟 1. 打開項目 在 VS Code 中打開你的前端項目文件夾。 2. 初始化 Git 倉庫&#xff08…

Flutter 導航與路由管理:Navigator 的深入解析與實踐

在移動應用開發中&#xff0c;頁面導航是用戶體驗的核心組成部分。Flutter 提供了強大而靈活的導航系統&#xff0c;主要通過 Navigator 組件來實現。本文將全面介紹 Flutter 中 Navigator 的使用方法&#xff0c;涵蓋基礎導航操作、進階技巧以及最佳實踐。 一、Flutter 導航系…

預測性去匿名化攻擊(PDAA):重塑數據安全攻防邊界

一、數據合規時代的“脫敏”悖論&#xff1a;價值釋放與風險并存 在數據驅動的商業模式與日趨嚴格的個人信息保護法規&#xff08;如《個人信息保護法》《數據安全法》&#xff09;雙重推動下&#xff0c;企業普遍將“數據脫敏”作為實現數據合規與價值釋放的核心手段。對手機…

[python] 使用python設計濾波器

使用python設計濾波器 文章目錄 使用python設計濾波器完整濾波器設計代碼&#xff08;未經完整驗證&#xff0c;博主還在不斷完善中&#xff09;關鍵原理與代碼對應說明1. 濾波器類型選擇2. 階數估算原理3. 性能分析技術4. 設計參數調整指南 習慣了python后&#xff0c;matlab逐…

mac電腦.sh文件,用來清除git當前分支

#!/bin/bashecho "正在檢查Git倉庫..." if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; thenecho "錯誤&#xff1a;當前目錄不是Git倉庫&#xff01;"exit 1 fiecho "警告&#xff1a;這將丟棄所有未提交的更改和本地提交&am…

Bash (Bourne Again SHell)

Unix/Linux 系統中最常用的命令行解釋器之一&#xff0c;它是原始 Bourne shell (sh) 的增強版本。以下是 Bash 的詳細解釋&#xff1a; 1. Bash 基礎 1.1 什么是 Bash 一個命令行解釋器&#xff0c;用于執行用戶輸入的命令支持腳本編程&#xff0c;可以編寫復雜的自動化任務…

uni-app學習筆記三十五--擴展組件的安裝和使用

由于內置組件不能滿足日常開發需要&#xff0c;uniapp官方也提供了眾多的擴展組件供我們使用。由于不是內置組件&#xff0c;需要安裝才能使用。 一、安裝擴展插件 安裝方法&#xff1a; 1.訪問uniapp官方文檔組件部分&#xff1a;組件使用的入門教程 | uni-app官網 點擊左側…

AIStor 的模型上下文協議 (MCP) 服務器: 工作原理

在本系列的前幾篇博文中&#xff0c;我們討論了MinIO AIStor 模型上下文協議 (MCP) 服務器的用戶級和管理員級功能。在第一篇博文中&#xff0c;我們學習了如何查看存儲桶的內容、分析對象并標記它們以便將來處理。在第二篇博文中&#xff0c;我們還學習了如何使用管理員命令以…