C++之類和對象:構造函數,析構函數,拷貝構造,賦值運算符重載

前提:如果一個類是空類,C++中空類中真的什么都沒有嗎,不是的,編譯器會自動生成6個默認成員函數。默認成員函數:用戶沒有顯式實現,編譯器會生成的成員函數稱為默認成員函數。

默認成員函數:構造函數,析構函數,拷貝構造函數,賦值運算符重載,取地址重載,const取地址重載。

構造函數(完成初始化):

我們在設計類的時候,在C語言中必須有一個初始化函數才好定義變量。在C++中類如果我們沒有寫這個初始化函數,那么編譯器就會默認生成一個默認構造函數。這個默認構造函數對內置類型不處理,自定義類型調用它的默認構造函數。

構造函數的調用:

class Data
{
public:Data(int year,int month,int day){_year = year;_month = month;_day = day;}
private://內置類型int _year = 2025;int _month = 4;int _day = 28;//自定義類型//Time _t;
};int main()
{Data day(2025,4,28);//調用帶參的構造函數return 0;
}

如果是無參的構造函數:Data day;? 即可,不要括號。?

構造函數的特性:

1.函數名與類名相同

2.無返回值

3.對象(也可以稱為自定義類型變量)實例化時編譯器自動調用對應的構造函數。

4.構造函數也可以重載。

5.如果類中沒有顯式定義構造函數,編譯器才會生成,一旦顯式定義就不會生成

6.編譯器生成的默認構造函數對內置類型不處理,自定義類型調用它的默認構造函數

7.無參的構造函數,全缺省的構造函數,編譯器自動生成的構造函數都是默認構造函數。

注意提醒:編譯器生成的默認構造函數對于自定義類型會自動調用它的默認構造函數,而如果我們自己寫了一個無參的構造函數就按照自己寫的內容來,不會自動調用。

還有一個容易混淆的點:編譯器自動生成的默認構造函數會自動調用自定義類型的默認構造函數,如果這個自定義類型的構造函數如果不是默認構造函數就會報錯。

//會報錯的代碼:
class Time
{
public://不是默認構造函數Time(int hour,int minute,int second){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}
private:int _hour;int _minute;int _second;
};class Data
{
private://內置類型int _year;int _month;int _day;//自定義類型Time _t;
};int main()
{Data day;return 0;
}

上述代碼 Data 類中就有 Time 自定義類型,但是構造函數不是默認構造函數所以報錯了。

//正確的代碼:
class Time
{
public://全缺省函數Time(int hour=0,int minute=0,int second=0){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}
private:int _hour;int _minute;int _second;
};class Data
{
private://內置類型int _year;int _month;int _day;//自定義類型Time _t;
};int main()
{Data day;return 0;
}

所以我們盡量使用全缺省構造函數。

還有對于編譯器自動生成的默認構造函數,針對內置類型不做處理,C++11有了內置類型成員在類中聲明時可以給默認值 就是在聲明時給缺省值:

析構函數(完成清理工作):

析構函數是在對象銷毀時完成對象中資源的清理工作,對象在銷毀時會自動調用析構函數。

析構函數不是銷毀對象本身,對象本身是由編譯器銷毀的。

析構函數的特性:

1.析構函數名是類名前面加字符~。

2.無參數也無返回值。

3.一個類只有一個析構函數,如果沒有顯式定義,編譯器會自動生成默認的析構函數,注意:析構函數不能重載。

4.對象生命周期結束時,系統會自動調用析構函數

5.編譯器生成的默認析構函數,對內置類型不做處理,對自定義類型調用它的析構函數。

6.如果類中有申請資源,例如:動態申請空間之類的需要手動銷毀,必須要寫析構函數手動銷毀,否則會造成資源泄漏。如果沒有資源申請則可以默認析構函數。

#include<iostream>
using namespace std;class Time
{
public:Time(int hour=0,int minute=0,int second=0){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}~Time(){cout << "Time析構函數" << endl;}
private:int _hour;int _minute;int _second;
};class Data
{
public:Data(int year,int month,int day){cout << "Data" << endl;_year = year;_month = month;_day = day;}~Data(){cout << "Data析構函數" << endl;}
private:int _year = 2025;int _month = 4;int _day = 28;
};int main()
{Data day(2025,4,28);Time TY;return 0;
}

?上述代碼讓我們明白系統調用析構函數的順序:局部對象(后定義先析構)-> 局部靜態對象 ->

全局對象(后定義先析構):

拷貝構造函數(同類對象初始化創建對象):

拷貝構造函數:只有單個形參,形參是本類類型對象的引用(一般用const修飾)用已存在的自定義類型對象創建新對象時由編譯器自動調用。

拷貝構造的特性:

1.拷貝構造函數是構造函數的一個重載形式。

2.拷貝構造函數的參數只有一個且必須是類類型對象的引用,使用傳值方式編譯器會報錯,會引發無盡遞歸調用。

3.如果類中沒有顯式定義拷貝構造,編譯器會生成默認拷貝構造函數,默認拷貝構造對內置類型按內存存儲按字節序完成拷貝,是值拷貝,或者叫淺拷貝。自定義類型調用它的拷貝構造。

4.編譯器的默認拷貝構造,只會完成淺拷貝,一旦類中有資源申請,拷貝構造函數必須要寫,例如:有動態內存管理,那么指向動態內存的指針,淺拷貝只會拷貝地址,不會生成相同的動態內存,會導致很多問題。

5.拷貝構造典型調用場景:使用已存在對象創建新對象 / 函數參數類型為類類型對象 / 函數返回值類型為類類型對象。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷貝構造" << endl;_year = d._year;_month = d._month;_day = d._day;}~Data(){cout << "Data析構函數" << endl;}
private://內置類型int _year;int _month;int _day;
};int main()
{Data day1;Data day2(day1);return 0;
}

?

當函數傳值傳參時或者返回值時調用拷貝構造:

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷貝構造" << endl;_year = d._year;_month = d._month;_day = d._day;}~Data(){cout << "Data析構函數" << endl;}
private://內置類型int _year;int _month;int _day;
};Data Test(Data d)
{Data tmp(d);return tmp;
}int main()
{Data day1;Test(day1);return 0;
}

?

實際過程中編譯器為了效率會減少一些拷貝構造優化拷貝構造。為了提高效率,一般對象傳參盡量使用引用類型,返回值看情況。

賦值運算符重載(把一個對象賦值給另一個對象):

運算符重載:

C++引入了運算符重載,運算符重載是具有特殊函數名的函數。

注意:1.不能通過連接其他符號來創建新操作符:operator@

2.重載操作符必須有一個類類型參數,不能去重載運算符改變內置類型的行為。

3.? .*? ?::? ?sizeof? ?:? .? ?以上五個運算符不能被重載。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷貝構造" << endl;_year = d._year;_month = d._month;_day = d._day;}//這里左操作數是this指針,指向調用函數的對象bool operator==(const Data& d2){return _year == d2._year && _month == d2._month && _day == d2._day;}~Data(){cout << "Data析構函數" << endl;}
private://內置類型int _year;int _month;int _day;
};int main()
{Data day1;Data day2(day1);cout << (day1 == day2) << endl;return 0;
}

?賦值運算符重載:

1.賦值運算符重載格式:1參數類型 const T& ,傳遞引用提高效率。2返回值類型 T& 支持連續賦值且提高效率。3檢查是否給自己賦值。4返回 *this,要符合連續賦值的含義。

2.賦值運算符只能重載成類的成員函數不能重載成全局函數。因為類中沒有顯式實現,編譯器會生成默認賦值運算符重載,如果在全局中也有一個,就沖突了。

3.編譯器生成的默認運算符重載,對內置類型淺拷貝,對自定義類型調用它的賦值運算符重載。

還是需要注意類中是否有資源申請,有的話必須要實現。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷貝構造" << endl;_year = d._year;_month = d._month;_day = d._day;}Data& operator= (const Data& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}bool operator== (const Data& d2){return _year == d2._year && _month == d2._month && _day == d2._day;}~Data(){cout << "Data析構函數" << endl;}
private://內置類型int _year;int _month;int _day;
};int main()
{Data day1(1,2,3);Data day2;day2 = day1;return 0;
}

和拷貝構造的區別:拷貝構造是一個存在的對象創建一個新對象并且賦值,賦值運算符重載是兩個存在的對象,一個給另一個賦值。

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

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

相關文章

【專題五】位運算(1):常見位運算操作總結

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的基礎算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&#xff…

小草GrassRouter多卡聚合路由器聚合衛星、MESH網絡應用解決方案

一、多網融合解決方案 衛星網絡融合? 支持接入衛星通信模塊&#xff0c;在無地面網絡覆蓋的極端場景&#xff08;如偏遠山區、海洋救援&#xff09;下&#xff0c;形成“5G衛星”雙鏈路冗余傳輸&#xff0c;衛星鏈路可作為核心通信備份&#xff0c;確保關鍵指令和視頻數據實…

【Mybatis】Mybatis基礎

文章目錄 前言一、搭建MyBatis1.1 創建maven工程1.2 加入log4j日志功能1.3 MyBatis的增刪改查1.4 核心配置文件詳解 二、MyBatis獲取參數值的兩種方式2.1 單個字面量類型的參數2.2 多個字面量類型的參數2.3 map集合類型的參數2.4 實體類類型的參數2.5 使用Param標識參數 三、 M…

AI四大邊界

大模型訓練的邊界并非由單一因素決定&#xff0c;而是技術、倫理、法律及實際應用需求共同作用的結果。以下從四個維度解析其邊界來源&#xff1a; 一、技術邊界&#xff1a;資源與能力的雙重限制 計算資源瓶頸 成本與算力&#xff1a;大模型訓練依賴海量GPU/TPU資源&#xff…

Twitter 工作原理|架構解析|社交APP邏輯

這是對Twitter 工作原理&#xff5c;架構解析&#xff5c;社交APP邏輯_嗶哩嗶哩_bilibili的學習&#xff0c;感謝up小凡生一 在兩年半前&#xff0c;埃隆馬斯克收購了Twitter&#xff0c;并且進行了一系列重大改革。今天我們來解析一下這個全球知名社交平臺的架構。首先&#x…

Java基礎學習內容大綱

Java基礎學習內容大綱 第一階段:建立編程思想 ? Java概述:如何快速學習Java技術、Java歷史、Java特點、Sublime、Java運行機制、JDK、轉義字符、Java開發規范、Java API ? 變量:數據類型、變量基本使用、數據類型轉換 ? 運算符:運算符介紹、算數運算符、關系運算符、…

如何對多維樣本進行KS檢驗

對于形狀為 ( 10000 , 1 , 304 ) (10000, 1, 304) (10000,1,304)的三維數據&#xff0c;若需使用scipy.stats.ks_2samp進行KS檢驗&#xff0c;可按以下步驟處理&#xff1a; 數據降維 KS檢驗要求輸入為一維數組&#xff0c;需將三維數據展平或按特定維度聚合&#xff1a; ? 方…

在 VMware 虛擬機中安裝 Windows7

文章目錄 前言1.安裝VMware 虛擬機1. VMware虛擬機軟件安裝2. 虛擬機創建配置&#xff08;超詳細步驟&#xff09;3. Windows7系統安裝 3、安裝 VMware tools4. VMware Tools安裝與優化5. 總結與常見問題 前言 最近有不少朋友在問如何在電腦上同時使用多個操作系統&#xff0c…

直播預告|TinyVue 組件庫高級用法:定制你的企業級UI體系

TinyVue 是一個跨端跨框架的企業級 UI 組件庫&#xff0c;基于 renderless 無渲染組件設計架構&#xff0c;實現了一套代碼同時支持 Vue2 和 Vue3&#xff0c;支持 PC 和移動端&#xff0c;包含 100 多個功能豐富的精美組件&#xff0c;可幫助開發者高效開發 Web 應用。 4 月 …

分治而不割裂—分治協同式敏捷工作模式

分治而不割裂&#xff1a;解密敏捷協同工作模式如何驅動大企業持續領跑 在數字化浪潮中&#xff0c;亞馬遜僅用11天完成Prime Day全球技術架構升級&#xff0c;華為5G基站項目組創造過單周迭代47個功能模塊的紀錄&#xff0c;這些商業奇跡的背后&#xff0c;都隱藏著一個共性秘…

Python列表全面解析:從基礎到高階操作

一、為什么需要列表&#xff1f; 在Python中&#xff0c;列表是可變有序序列&#xff0c;用于存儲多個元素的容器。相較于單一變量存儲獨立值&#xff0c;列表能更高效地管理批量數據&#xff0c;其特點包括&#xff1a; ?引用存儲&#xff1a;列表元素存儲的是對象的引用?…

Spring知識點梳理

一、Spring&#xff08;Spring Framework&#xff09; 1、IOC&#xff08;控制反轉&#xff09; 1&#xff09;什么是IOC控制反轉&#xff1f; 為了解藕&#xff0c;有反轉就有“正轉”&#xff0c;“正轉”就是程序員手動 new對象&#xff1b;“反轉”就是將對象的創建、對…

SpringBoot啟動后自動執行方法的各種方式-筆記

1. SpringBoot啟動后自動執行方法的各種方式 1.1 PostConstruct 注解 作用&#xff1a;在依賴注入完成后執行初始化方法。 適用場景&#xff1a;需要在Bean初始化時執行某些操作&#xff08;如配置、預加載數據&#xff09;。 注意&#xff1a;該方法在Bean初始化階段執行&…

基礎知識-java流steam

Java Stream 流詳解 一、Stream 概述 #mermaid-svg-ZXmu5UZgAcGGq8EN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZXmu5UZgAcGGq8EN .error-icon{fill:#552222;}#mermaid-svg-ZXmu5UZgAcGGq8EN .error-text{fil…

8.Android(通過Manifest配置文件傳遞數據(meta-data))

配置文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><applicationandroid:allowBackup"tr…

java 解析入參里的cron表達式,修改周時間

文章目錄 前言一、java 解析入參里的cron表達式,修改周時間二、使用步驟1.示例 總結 前言 一、java 解析入參里的cron表達式,修改周時間 示例&#xff1a; 第一種: 0 0 0,16 ? * 0,1 第2種 0 0 0,16 ? * 1-7 第3種 0 0 0,16 ? * ? 第4種 0 0 0,16 ? * * 二、使用步驟 1…

DTO,VO,PO,Entity

1. DTO (Data Transfer Object) 定義 DTO 是數據傳輸對象&#xff0c;用于在不同系統或層之間傳輸數據。 目的 簡化數據傳輸&#xff0c;降低耦合&#xff0c;通常只包含需要傳輸的字段&#xff0c;避免暴露內部實現細節。 使用場景 Controller 和 Service 或 遠程調用 之…

從零搭建高可用分布式限流組件:設計模式與Redis令牌桶實踐

一、需求背景與設計目標 在分布式系統中&#xff0c;面對突發流量時需要一種精準可控的流量控制手段。我們的組件需要具備&#xff1a; 多維度限流&#xff08;用戶/IP/服務節點/自定義表達式&#xff09;分布式環境下精準控制開箱即用的Spring Boot Starter集成高擴展性的架…

Node.js 事件循環和線程池任務完整指南?

在 Node.js 的運行體系中&#xff0c;事件循環和線程池是保障其高效異步處理能力的核心組件。事件循環負責調度各類異步任務的執行順序&#xff0c;而線程池則承擔著處理 CPU 密集型及部分特定 I/O 任務的工作。接下來&#xff0c;我們將結合圖示&#xff0c;詳細剖析兩者的工作…

echarts自定義圖表--儀表盤

基于儀表盤類型的自定義表盤 上圖為3層結構組成 正常一個儀表盤配置要在外圈和內圈之間制造一條縫隙間隔 再創建一個儀表盤配置 背景透明 進度條拉滿 進度條顏色和數據的背景相同開始處的線 又一個儀表盤配置 數值固定一個比較小的值 <!DOCTYPE html> <html><h…