【C++】拷貝構造函數,析構函數詳解!

在這里插入圖片描述

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃個人主頁 :阿然成長日記 👈點擊可跳轉
📆 個人專欄: 🔹數據結構與算法🔹C語言進階
🚩 不能則學,不知則問,恥于問人,決無長進
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍

文章目錄

  • 一、析構函數
    • 1.概念
    • 2.特點
    • 3.案例
  • 二、拷貝構造函數
    • 1.拷貝構造函數的引入
    • 2.格式
    • 2.概念
    • 3.特點
    • 4.解決引入問題
    • 5.總結

一、析構函數

1.概念

析構函數:與構造函數功能相反,析構函數不是完成對對象本身的銷毀,局部對象銷毀工作是由
編譯器完成的。而對象在銷毀時會自動調用析構函數,完成對象中資源的清理工作。
析構函數是用于在對象被刪除之前的清理工作,它在對象生命周期即將結束時會被自動調用。(析構函數可以清理對象并且釋放內存)

2.特點

析構函數是特殊的成員函數,其特征如下:

  1. 析構函數名是在類名前加上字符 ~
  2. 無參數無返回值類型。
  3. 一個類只能有一個析構函數。若未顯式定義,系統會自動生成默認的析構函數。注意:析構
    函數不能重載
  4. 對象生命周期結束時,C++編譯系統系統自動調用析構函數
  5. 關于編譯器自動生成的析構函數,是否會完成一些事情呢?下面的程序我們會看到,編譯器
    生成的默認析構函數,對自定類型成員調用它的析構函數

3.案例

class Time
{
public:
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本類型(內置類型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定義類型
Time _t;
};
int main()
{
Date d;
return 0;
}

上述代碼定義了兩個類Data和Time。其中Data類中存在一個自定義類型變量Time,主方法中只創建了Data對象。那么在main方法中根本沒有直接創建Time類的對象,為什么最后會調用Time類的析構函數?

答:因為main方法中創建了Date對象d,而d中包含4個成員變量,其中_year, _month,_day三個是內置類型成員,銷毀時不需要資源清理,最后系統直接將其內存回收即可;而_tTime類對象,所以在d銷毀時,要將其內部包含的Time類的_t對象銷毀,需要調用Time類的析構函數。但是main函數中不能直接調用Time類的析構函數,實際要釋放的是Date類對象,所以編譯器只會調用Date類的析構函 數,而Date沒有顯式提供,則編譯器會給Date類生成一個默認的析構函數,目的是在其內部 調用Time類的析構函數,即當Date對象銷毀時,要保證其內部每個自定義對象都可以正確銷毀 ,main函數中并沒有直接調用Time類析構函數,而是顯式調用編譯器為Date類生成的默認析構函數
注意:創建哪個類的對象則調用該類的析構函數,銷毀那個類的對象則調用該類的析構函數

二、拷貝構造函數

1.拷貝構造函數的引入

如下代碼:
創建Stack類和Date類。

class Date
{
public:void print(){}
private:int _year =1;int _month =1;int _day =1;
};
class Stack
{public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申請空間失敗");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}private:int* _array;size_t _size;size_t _capacity;
};

使用傳值的方式進行調用。

void fun1(Date d)
{//...
}
void fun2(Stack s)
{//...
}

主函數

int main()
{Date d1(1999, 1, 1);fun1(d1);Stack s1;fun2(s1);return 0;
}

在這里插入圖片描述

可以發現運行報錯!!!為什么呢?

在C語言中我們遇到這種情況是沒有問題的,但是在C++中,由于引進了析構函數,也就是說每次對象試用結束,系統都會自動調用析構函數進行對象的清除工作,正因如此我們在傳值的時候,會再次創建一個對象復制過去,當結束函數調用時,會自動調用析構函數對當前對象進行清除,【如果對象中都是變量的話是沒有問題的,因為值傳遞的改變不影響外部的變量,它只是一份拷貝。但是,如果對象中有指針類型的變量,它們指向的是同一位置,第一次函數調用結束后,析構函數已經對指向的位置進行了清除,第二次外部對象結束時,在調用析構函數,就會造成二次析構】。上面例子中Date類中全是普通變量,不會出現問題,造成二次析構。
為了解決上面的問題我們引入了拷貝構造函數。(通過深拷貝解決問題)

2.格式

類名(const 類名 &參數)

2.概念

只能有單個形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存 在的類類型對象創建新對象時由編譯器自動調用。

3.特點

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

例如:

class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{_year = year;_month = month;_day = day;
}
下面是拷貝構造!!
Date(const Date& ddd) // 正確寫法
Date(const Date ddd) // 錯誤寫法:編譯報錯,會引發無窮遞歸
{_year = d._year;_month = d._month;_day = d._day;
}
private:int _year;int _month;int _day;
};

主函數

int main()
{Date d1;Date d2(d1);return 0;
}
  • Date(const Date d) // 錯誤寫法:編譯報錯,會引發無窮遞歸; 因為【Date d】參數會繼續生成一個拷貝構造,如此往復循環。
  • *Date(const Date& ddd) // 正確寫法 使用傳引用就可以解決這個問題。因為ddd就是對象d1的一個別名,this指針指向d2,ddd傳給了this,就相當于把d1給了d2,(傳遞指針也可以,但是很難用),規定必須使用引用。

4.解決引入問題

學到這里我們就可以很好地解決之前拋出的問題了。使用拷貝構造,將原來對象玩玩整整的拷貝一份出來,尤其是內部指針所指向的空間,拷貝時也會去開辟一塊新的空間。這樣在函數調用函數結束時,系統自動調用其析構造函數時,就不會造成一個地方多次析構了。各玩各的。

5.總結

內置類型系統會默認生成拷貝構造進行值拷貝,對自定義類型調用它的拷貝構造。
并不是所有的對象都需要拷貝構造:

  • 類中如果沒有涉及資源申請時(例如 new申請空間),拷貝構造函數是否寫都可以;
  • 一旦涉及到資源申請時,則拷貝構造函數是一定要寫的,否則就是淺拷貝。
  • 拷貝構造也是構造,是拷貝構造的一個重載。

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

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

相關文章

【LeetCode】挑戰100天 Day13(熱題+面試經典150題)

【LeetCode】挑戰100天 Day13&#xff08;熱題面試經典150題&#xff09; 一、LeetCode介紹二、LeetCode 熱題 HOT 100-152.1 題目2.2 題解 三、面試經典 150 題-153.1 題目3.2 題解 一、LeetCode介紹 LeetCode是一個在線編程網站&#xff0c;提供各種算法和數據結構的題目&…

Vue3 實現elementPlus的table列寬調整和拖拽

1、需要的包 // 除了Vue和element-plus外還需要以下的包 npm install sortablejs2、具體代碼如下&#xff0c;可直接粘貼運行 <template><div class"draggable-table"><el-table ref"tableRef":data"tableData.data":key"…

Java-飛翔的小鳥

前言 基于Java的飛翔小鳥游戲&#xff0c;本代碼來自b站up主分享。本游戲所需的圖片素材需要自己獲取并下載&#xff0c;在此視頻下&#xff0c;視頻鏈接&#xff1a;【Java經典小游戲項目之飛翔的小鳥】 https://www.bilibili.com/video/BV1ou411o7br/?p10&share_source…

C#編程題分享(4)

換行輸出整數問題 輸?任意?個位數未知的整數&#xff0c;輸出這個數每?位上的數字。輸出的時候&#xff0c;從個位開始輸出&#xff0c;每輸出?個數字換??。樣例輸?&#xff1a;3547 輸出&#xff1a;7 換行輸出 4 換行輸出5 換行輸出3 int n Convert.ToInt32(Conso…

【python基礎(九)】文件和異常詳解:使用、讀取、寫入、追加、保存用戶的信息,以及優雅的處理異常

文章目錄 一. 從文件中讀取數據1. 讀取整個文件2. 文件路徑3. 逐行讀取4. 創建一個包含文件各行內容的列表 二. 寫入文件1. 寫入空文件2. 寫入多行3. 附加到文件 三. 異常1. 處理ZeroDivisionError異常2. 使用try-except代碼塊3. try-except-else ing4. 處理FileNotFoundError異…

如何在AD上創建完整的項目

首先&#xff0c;我們先安裝好AD&#xff0c;這里我使用的是AD22&#xff0c;安裝過程如下&#xff1a; Altium Designer 22下載安裝教程-CSDN博客 Altium Designer 22是全球領先的PCB設計軟件之一&#xff0c;為電路板設計師提供了一種集成的解決方案&#xff0c;旨在簡化和加…

探討工業元宇宙和數字孿生的關系

就在各類技術專家還在試圖設想元宇宙虛擬世界將為企業和消費者帶來什么時&#xff0c;工業元宇宙虛擬世界已經在改變人們設計、制造以及與各行業物理實體互動的方式。盡管元宇宙的定義比比皆是&#xff0c;工業元宇宙將如何發展還有待觀察&#xff0c;但數字孿生越來越多地被視…

shell(函數和數組)

目錄 一、函數 1.函數的由來 2.函數的作用 3.函數的使用方法 4.函數的定義 5.查看函數 6.刪除函數 7.函數返回值 8.函數的傳參數 9.函數遞歸 二、數組 1.數組的相關介紹 2.聲明數組 3.定義數組的格式 4.冒泡排序 總結&#xff1a;本章主要介紹了函數和數組相關知…

運維 在Windows上搭建小型Git服務

文章目錄 1、Git選型1.1、主要特性1.2、代碼管理1.3、工單管理1.4、Pull/Merge requests1.5、第三方集成1.6、選型結論 2、環境搭建2.1、Gitea下載2.2、Gitea安裝2.3、配置服務信息2.4、運行服務2.5、注冊Gitea為服務2.6、正常使用 1、Git選型 1.1、主要特性 1.2、代碼管理 1.…

多數據庫使用django-apscheduler時,migrate后并不能生成django_apscheduler_djangojob表的問題

先說一下django-apscheduler定時器的使用過程&#xff1a; django-apscheduler基本使用 1.安裝django-apscheduler代碼如下&#xff08;示例&#xff09;&#xff1a; pip install django-apscheduler 2.配置settings.py的INSTALLED_APPS代碼如下&#xff08;示例&#xff09…

項目中常用的 19 條 SQL 優化寶典

一、EXPLAIN 做MySQL優化,我們要善用 EXPLAIN 查看SQL執行計劃。 下面來個簡單的示例,標注(1,2,3,4,5)我們要重點關注的數據 type列,連接類型。一個好的sql語句至少要達到range級別。杜絕出現all級別 key列,使用到的索引名。如果沒有選擇索引,值是NULL。可以采取強制索引…

【CCF-PTA】第03屆Scratch第01題 -- 夢醒時分

夢醒時分 【題目描述】 睡眠是人體正常的生理需要&#xff0c;同年齡男女睡眠時間無明顯差別&#xff0c;一般是8小時左右。居家的小明作息生活很規律&#xff0c;晚上11點睡覺&#xff0c;早晨7點起床學習。請你編寫程序來判斷&#xff0c;每周&#xff08;共168小時&#x…

【JavaEE初階】 JavaScript相應的WebAPI

文章目錄 &#x1f332;WebAPI 背景知識&#x1f6a9;什么是 WebAPI&#x1f6a9;什么是 API &#x1f38d;DOM 基本概念&#x1f6a9;什么是 DOM&#x1f6a9;DOM 樹 &#x1f340;獲取元素&#x1f6a9;querySelector&#x1f6a9;querySelectorAll &#x1f384;事件初識&am…

不是吧?線程池這樣搞?

其他系列文章目錄 設計模式合集 多線程合集 分布式合集 ES合集 文章目錄 系列文章目錄 前言 一、為什么需要線程池&#xff1f; 二、舉個背景例子 三、怎么創建線程池&#xff1f; 四、線程池指定線程數 前言 學習線程池能夠幫助我們更好地處理多線程編程&#xff0c;并提高程…

TikTok美區本土店鋪如何做好IP隔離?

為什么要進行IP隔離呢&#xff1f;因為我們無法在國內直接運營Shopee、TikTok、Lazada等平臺的本土店&#xff0c;平臺識別出店鋪登錄IP非本土IP&#xff0c;則容易導致店鋪風控、被標記為偽本土店&#xff0c;影響店鋪經營。 TikTok美區店鋪的IP隔離方法和Shopee本土店一致&a…

SpringMVC(二)

八、HttpMessageConverter HttpMessageConverter&#xff0c;報文信息轉換器&#xff0c;將請求報文轉換為Java對象&#xff0c;或將Java對象轉換為響應報文 HttpMessageConverter提供了兩個注解和兩個類型&#xff1a;RequestBody&#xff0c;ResponseBody&#xff0c;Reque…

【MySQL】子查詢

文章目錄 子查詢IN運算符子查詢 VS 連接ALL關鍵字ANY關鍵字相關子查詢 !EXISTS運算符select子句中的子查詢from子句中的子查詢 子查詢 獲取價格大于id為3的貨物的商品 用到了內查詢&#xff0c;獲取id為3的商品的單價&#xff0c;把結構傳給外查詢 在where子句中編寫子查詢&am…

【python基礎(四)】if語句詳解

文章目錄 一. 一個簡單示例二. 條件測試1. 檢查多個條件1.1. 使用and關聯多個條件1.2. 使用or檢查多個條件1.3. in的判斷 2. 布爾表達式 三. if語句1. 簡單的if語句2. if-else語句3. if-elif-else結構4. 使用多個elif代碼塊5. 省略else代碼塊 四. 使用if語句處理列表1. 檢查特殊…

2023-11-23 LeetCode每日一題(HTML 實體解析器)

2023-11-23每日一題 一、題目編號 1410. HTML 實體解析器二、題目鏈接 點擊跳轉到題目位置 三、題目描述 「HTML 實體解析器」 是一種特殊的解析器&#xff0c;它將 HTML 代碼作為輸入&#xff0c;并用字符本身替換掉所有這些特殊的字符實體。 HTML 里這些特殊字符和它們…

Endnote軟件添加期刊引用格式

在下述網址中&#xff0c;找到你想要添加的期刊&#xff0c;下載引用格式文件&#xff08;后綴為.ens格式&#xff09; https://endnote.com/downloads/styles/?wpv_post_searchInformationfusion&wpv_aux_current_post_id12829&wpv_view_count12764-TCPID12829 下載…