類和對象(中):類的默認成員函數、構造函數、析構函數

🔥個人主頁:胡蘿卜3.0

🎬作者簡介:C++研發方向學習者

📖個人專欄:??《C語言》《數據結構》?《C++干貨分享》

??人生格言:不試試怎么知道自己行不行


目錄

一、類的默認成員函數

二、構造函數

三、析構函數


一、類的默認成員函數

默認成員函數就是用戶沒有顯示實現,編譯器會自動生成的成員函數成為默認成員函數。

在一個類中,我們不寫的情況下編譯器會默認生成6個默認成員函數:

在這6個中最重要的是前4個,最后兩個取地址重載不是很重要,我們稍微了解一下即可。其次就是C++11以后還會增加兩個默認成員函數:移動構造和移動賦值,這個我們后面再講解。默認成員函數很重要,也很復雜,我們要從兩個方面去學習

  1. 第一:我們不寫時,編譯器默認生成的函數行為是什么,是否滿足我們的需求。
  2. 第二:編譯器默認生成的函數不滿足我們的需求,我們需要自己實現,那么自己如何實現?

二、構造函數

有同學看到這個標題,就想說構造函數有什么好學的,不就是給對象開辟空間嗎?不用學的,不用學的~~。

ok,構造函數雖然名稱叫構造,但是構造函數的主要任務并不是開空間創建對象(我們常使用的局部對象是棧幀創建時,空間就開好了),構造函數的主要任務是對象實例化時初始化對象。構造函數的本質是要替代我們以前Stack和Date類中寫的Init函數(初始化函數)的功能,構造函數自動調用的特點就完美的替代了Init函數。構造函數完成初始化,初始化對象,不是開辟空間,并且構造函數是一個特殊的成員函數,接下來我們來看看它到底特殊在哪里。

構造函數的特點:

  1. 函數名和類名相同
  2. 無返回值。(返回值啥都不需要給,也不需要寫void,這里不要糾結,只要記得這是C++的規定)
  3. 對象實例化是系統會自動調用對應的構造函數。
  4. 構造函數可以重載。(在一個類里面可能需要多種初始化方式)
  5. 如果類中沒有顯示定義構造函數,則C++編譯器會自動生成一個無參的默認構造函數,一旦用戶顯示定義構造函數,編譯器將不在生成
  6. 無參構造函數、全缺省構造函數、我們不寫構造是編譯器默認生成的構造函數,都叫做默認構造函數,但是這三個函數有且只有一個存在,不能同時存在。無參構造函數和全缺省構造函數雖然構成函數重載,但是調用時會存在歧義。要注意很多同學會認為默認構造函數是編譯器默認生成那個叫默認構造,實際上無參構造函數、全缺省構造函數也是默認構造,總結?下就是不傳實參就可以調用的構造就叫默認構造。
  7. 我們不寫,編譯器默認生成的構造,對內置類型成員變量的初始化沒有要求,也就是說是否初始化是不確定的,要看編譯器。對于自定義類型成員變量,要求調用這個成員變量的默認構造函數初始化。如果這個成員變量,沒有默認構造函數,那么就會報錯,我們要初始化這個成員變量,需要用初始化列表才能解決,初始化列表,我們下個章節再細細講解。
    ?

ok,我們先看構造函數的前四個特點,通過上面的四點,我們就可以寫出一個構造函數了:

class Date
{
public://不傳參Date(){_year = 1;_month = 1;_day = 1;}//傳參Date(int year,int month,int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:// 內置類型int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();Date d2(2025,8,4);d2.Print();return 0;
}

有同學看到上面的代碼,就在想,怎么給出了兩個函數名都是Date的函數?這是因為構造函數是可以重載的,編譯器根據參數,匹配相應的函數。

這時候又有其他的小伙伴看到Date d2(2025,8,4);,這個構造函數在傳參,并且有括號,就在想要不要給Date d1;的后面加個括號呢?

其實這里是不需要的,原因如下:

注意:當構造函數有形參時加上括號,沒有參數不需要加上括號

那這時候就會有同學要問了,那構造函數與我們之前寫的Init函數的區別是什么?為什么不想要Init函數?

Init函數是分離的,也就是對象的定義和初始化是分離的,先定義,后初始化,這就會導致忘記初始化,C++這個機制是為了保證對象定義實例化出來就一定初始化,因為對象實例化時會自動調用對應的構造函數,也就意味著只要寫了正確的構造函數,對象實例化出來一定

接下來,我們來看一下后三點(后三點比較重要):

特點5:如果類中沒有顯示定義構造函數,則C++編譯器會自動生成一個無參的默認構造函數,一旦用戶顯示定義構造函數,編譯器將不在生成

話不多說,直接看代碼

代碼1(類中沒有顯示定義的構造函數):

class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day<<endl;}
private:// 內置類型int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();return 0;
}

為什么我沒有在類中定義構造函數,編譯器默認生成的構造函數給我的d1初始化成了隨機值呢?(后面再看)?

?代碼2(類中顯示定義構造函數):

class Date
{
public:Date()//無參構造函數{_year = 2025;_month = 8;_day = 3;}void Print(){cout << _year << "/" << _month << "/" << _day<<endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();return 0;
}

ok啊,當我們在類中顯示定義了構造函數,編譯器沒有自動生成一個無參的默認構造函數

?我們知道構造函數是默認成員函數中的一種,默認成員函數是我們不寫編譯器自動生成。那這時就有同學想說了,默認構造函數不就是我們不寫編譯器自動生成的構造函數嗎?這種想法是錯誤的

特點6:默認構造函數包括無參構造函數、全缺省構造函數、我們不寫時編譯器默認生成的構造函數

在這三個默認構造函數中,當我們寫構造函數時,有且只有一個存在,不能同時存在。無參構造函數和全缺省構造函數雖然構成函數重載,但是調用時會存在歧義。

注意的是很多同學會認為默認構造函數是編譯器默認生成的那個叫默認構,實際上無參構造、全缺省構造也是默認構造

總結:不傳實參就可以調用的構造就是默認構造

class Date
{
public://全缺省構造函數Date(int year=2025, int month=8, int day=1){_year = year;_month = month;_day = day;}//無參構造函數Date(){_year = 2025;_month = 8;_day = 3;}void Print(){cout << _year << "/" << _month << "/" << _day<<endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();return 0;
}

注意:無參構造和全缺省構造不能同時出現

補充:

?


通過上面的學習,我們知道如何寫一個構造函數了,那默認生成的構造會怎么處理成員呢?ok,接下來我們接著看:

特點7:我們不寫,編譯器默認生成的構造,對內置類型成員變量的初始化沒有要求,也就是說是否初始化是不確定的,要看編譯器,但是對于這種模棱兩可的行為,我們要當成內置類型不被處理。

對于自定義類型成員變量,要求調用這個成員變量的默認構造函數初始化。如果這個成員變量,沒有默認構造函數,那么就會報錯,我們要初始化這個成員變量,需要用初始化列表才能解決,初始化列表,我們下個章節再細細講解。

上面這兩段話中,對內置類型的處理很好理解,這對自定義類型成員變量的處理是啥意思?

總結:絕大多數情況下,構造函數都要我們自己寫,一般寫全缺省參數構造函數?

解答一下前面的問題:
?

三、析構函數

析構函數與構造函數功能相反,析構函數不是完成對對象本身的銷毀,比如:局部對象是存在棧幀的,函數結束棧幀銷毀,他就釋放了,不需要我們管。C++規定對象在銷毀時會自動調用析構函數,完成對象中資源的清理釋放工作。

析構函數的功能可以類比我們之前Stack實現的Destroy功能,而像我們上面寫的Date就沒有Destroy,其實就是沒有資源需要釋放,所以嚴格說Date是不需要析構函數的。
我們可以簡單的理解,析構函數是對類中所申請的空間進行釋放

析構函數的特點:

  1. 析構函數名是在類名前加上字符 ~。
  2. 無參數無返回值。 (這里跟構造類似,也不需要加void)
  3. ?個類只能有一個析構函數。若未顯式定義,系統會自動生成默認的析構函數。
  4. 對象生命周期結束時,系統會自動調用析構函數。
  5. 跟構造函數類似,我們不寫編譯器自動生成的析構函數對內置類型成員不做處理,自定類型成員會調用他的析構函數。
  6. 還需要注意的是我們顯示寫析構函數,對于自定義類型成員也會調用他的析構,也就是說自定義類型成員無論什么情況都會自動調用析構函數。
  7. ?個局部域的多個對象,C++規定后定義的先析構。

ok,我們先來看前四點,通過前四點,我們就知道如何寫一個析構函數了:

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day =day;}~Date(){cout << "~Date()" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;return 0;
}

當函數結束時,系統自動調用析構函數

class Stack
{
public:Stack(int n = 4){_a = (int*)malloc(n * sizeof(int));_top = 0;_capacity = n;}~Stack(){cout << "~stack()" << endl;if (_a){free(_a);_a = nullptr;_top = 0;_capacity = 0;}}
private:int* _a;int _top;int _capacity;
};
int main()
{Stack s1;return 0;
}

特點5:跟構造函數類似,我們不寫編譯器自動生成的析構函數對內置類型成員不做處理,自定類型成員會調用他的析構函數。

上面操作對內置類型成員的處理很簡單,我們來看看對自定義類型的處理是啥意思:

?

特點6:?我們顯示寫析構函數,對于自定義類型成員也會調用他的析構,也就是說自定義類型成員無論什么情況都會自動調用析構函數。

演示代碼:

class Stack
{
public:Stack(int n = 4){_a = (int*)malloc(n * sizeof(int));_top = 0;_capacity = n;}~Stack(){cout << "~stack()" << endl;if (_a){free(_a);_a = nullptr;_top = 0;_capacity = 0;}}
private:int* _a;int _top;int _capacity;
};
class MyQueue
{
public:~MyQueue( ){cout << "~myqueue()" << endl;}
private:Stack _pushst;Stack _popst;
};
int main()
{MyQueue q;return 0;
}

總結:
如果類中沒有申請資源時,析構函數可以不寫,直接使用編譯器生成的默認析構函數,如Date;如果默認生成的析構函數就可以用,也就不需要顯示寫析構,如MyQueue;但是有資源申請時,?定要自己寫析構,否則會造成資源泄漏,如Stack。

?

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

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

相關文章

如何優雅地刷力扣 LeetCode - Easy

Source 力扣LeetCode題庫 App > LeetCode > 題庫 > 題解 Notes 仔細審題&#xff0c;明確輸入輸出&#xff0c;通過測試用例。先特殊&#xff0c;后尋常。逆向思維。 在條件語句中用!代替&#xff0c;提前終止循環&#xff0c;減少嵌套層級&#xff08;else&#…

AI繪畫:生成唐初程咬金全身像提示詞

根據唐代歷史記載和藝術形象特征&#xff0c;以下是優化后的中文Midjourney 提示詞&#xff0c;突出程咬金的猛將氣質與唐初甲胄細節&#xff1a; 核心提示詞&#xff08;戰場形象&#xff09; 中年猛將程咬金&#xff0c;全身甲胄像&#xff0c;唐初光要甲制式&#xff1a;身…

【實時Linux實戰系列】實時數據流處理框架分析

背景與重要性在當今數字化時代&#xff0c;數據的實時處理變得至關重要。無論是金融交易、工業自動化還是物聯網&#xff08;IoT&#xff09;設備&#xff0c;都需要能夠快速處理和響應數據流&#xff0c;以確保系統的高效運行和決策的及時性。實時Linux操作系統因其低延遲和高…

一周學會Matplotlib3 Python 數據可視化-Hello World編寫

鋒哥原創的Matplotlib3 Python數據可視化視頻教程&#xff1a; 2026版 Matplotlib3 Python 數據可視化 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili Matplotlib3簡介 Matplotlib 是 Python 最流行的數據可視化庫之一&#xff0c;廣泛應用于科學計算、數據分析、科研繪…

中國MCP市場:騰訊、阿里、百度的本土化實踐

中國MCP市場&#xff1a;騰訊、阿里、百度的本土化實踐 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般絢爛的技術棧中&#xff0c;我是那個永不停歇的色彩收集者。 &#x1f98b; 每一個優化都是我培育的花朵&#xff0c;每一個特性都是我放飛的…

房產證識別在房產行業的技術實現及應用原理

技術實現1. 圖像采集與預處理圖像獲取&#xff1a;通過高分辨率掃描儀或手機攝像頭獲取房產證圖像預處理技術&#xff1a;去噪處理&#xff08;消除掃描噪聲&#xff09;圖像增強&#xff08;提高對比度&#xff09;傾斜校正&#xff08;自動旋轉至正確角度&#xff09;二值化處…

決策樹技術詳解:從理論到Python實戰

?決策樹像人類的思考過程&#xff0c;用一系列“是/否”問題層層逼近答案?一、決策樹的核心本質決策樹是一種模仿人類決策過程的樹形結構分類/回歸模型。它通過節點&#xff08;問題&#xff09;?? 和 ?邊&#xff08;答案&#xff09;?? 構建路徑&#xff0c;最終在葉節…

Herd-proof thinking

Let’s dive into “herd-proof thinking” — the mindset and tactics that help you stay sharp, independent, and immune to manipulative systems.&#x1f9e0; Part 1: The Foundation of Herd-Proof Thinking 1. Recognize Incentives“If you don’t know who the pr…

day068-DevOps基本知識與搭建遠程倉庫

文章目錄0. 老男孩思想-傳統文化1. 運維人員對網站集群的關注項2. CI、CD3. DevOps4. 環境5. Git5.1 **為什么叫 “Git”&#xff1f;**5.2 Git的核心設計理念5.3 Git工作空間5.4 分支 branch5.5 命令5.5.1 配置git用戶信息5.5.2 初始化git倉庫5.5.3 將文件放入暫存區5.5.4 提交…

分布式文件系統07-小文件系統的請求異步化高并發性能優化

小文件系統的請求異步化高并發性能優化222_分布式圖片存儲系統中的高性能指的到底是什么&#xff1f;重構系統架構&#xff0c;來實現一個高性能。然后就要做非常完善的一個測試&#xff0c;最后對這個系統做一個總結&#xff0c;說說后續我們還要做一些什么東西。另外&#xf…

【C#補全計劃:類和對象(十)】密封

一、密封類1. 關鍵字&#xff1a;sealed2. 作用&#xff1a;使類無法再被繼承&#xff1b;在面向對象設計中&#xff0c;密封類的主要作用是不允許最底層子類被繼承&#xff0c;可以保證程序的規范性、安全性3. 使用&#xff1a;using System;namespace Sealed {// 使用sealed關…

【視覺識別】Ubuntu 22.04 上安裝和配置 TigerVNC 魯班貓V5

系列文章目錄 文章目錄系列文章目錄前言一、問題現象二、安裝和配置步驟1.引入庫2.安裝完整組件3.修改 ~/.vnc/xstartup4. 設置權限5. 設置開機自啟&#xff08;Systemd 服務&#xff09;總結前言 開發平臺&#xff1a;魯班貓V5 RK3588 系統版本&#xff1a;Ubuntu 22.04 一、…

模擬-38.外觀數列-力扣(LeetCode)

一、題目解析1、替換的方法&#xff1a;“33”用“23”替換&#xff0c;即找到相同的數&#xff0c;前一位為相同數的數量&#xff0c;后一位為相同的數2、給定n&#xff0c;需要返回外觀數列的第n個元素二、算法原理由于需要統計相同元素的數目&#xff0c;所以可以使用雙指針…

垃圾桶滿溢識別準確率↑32%:陌訊多模態融合算法實戰解析

原創聲明本文為原創技術解析文章&#xff0c;涉及的技術參數與架構設計均參考自《陌訊技術白皮書》&#xff0c;轉載請注明來源。一、行業痛點&#xff1a;智慧環衛中的識別難題隨著智慧城市建設推進&#xff0c;垃圾桶滿溢識別作為智慧環衛的核心環節&#xff0c;面臨多重技術…

掃地機器人的幾種語音控制芯片方案介紹

?掃地機器人語音控制芯片方案介紹在智能家居領域&#xff0c;掃地機器人的智能化程度不斷提升&#xff0c;語音控制功能成為提升用戶體驗的關鍵因素。以下為您介紹幾款常用于掃地機器人語音控制的芯片方案。WT2606B 芯片方案性能優勢&#xff1a;基于先進的 RISC - V 32 位開源…

快速開發實踐

基于后端項目的前端開發實踐記錄 &#x1f4cb; 項目概述 項目名稱: 比特奧定制報表系統 技術棧: Vue 3 Element Plus Vite (前端) Spring Boot (后端) 開發模式: 前后端分離 項目結構: 單體倉庫包含前后端代碼 &#x1f3d7;? 項目架構分析 目錄結構設計 bitao-defined_re…

NFC 三大模式對比

以前以為nfc只是點對點通訊&#xff0c;沒想到現在nfc的功能很強大NFC 三大模式對比&#xff08;回顧&#xff09;模式作用手機是...Reader 模式讀取卡、標簽內容主動設備&#xff08;讀卡器&#xff09;Card Emulation 模式模擬公交卡/門禁卡/銀行卡被動設備&#xff08;卡&am…

JSON、JSONObject、JSONArray詳細介紹及其應用方式

第一部分&#xff1a;什么是JSON?&#x1f31f;比喻&#xff1a;JSON 是「快遞公司統一的 “通用快遞單”」&#x1f4a1;場景代入你想給朋友寄生日禮物&#xff08;比如一臺 “游戲機”&#xff09;&#xff0c;這臺游戲機有自己的屬性&#xff1a;名稱&#xff1a;"游戲…

Linux系統編程--權限管理

權限管理第二講 權限管理1. Shell命令以及運行原理1.1 知識引入1.2 概念介紹1.3 具體示例2. Linux權限問題2.1 權限概念2.2 用戶分類2.3 切換用戶2.4 用戶提權2.5 文件權限管理2.5.1 文件訪問者的分類&#xff08;角色&#xff09;2.5.2 文件類型和訪問權限&#xff08;事物屬性…

【智能硬件】X86和ARM架構的區別

詳細解釋X86架構和ARM架構之間的區別以及它們各自的特點。X86 架構定義與歷史定義&#xff1a;X86是一種計算機處理器體系結構&#xff0c;最初由英特爾公司開發。它是一系列指令集的集合體。歷史&#xff1a;最早的X86架構是Intel 8086處理器&#xff0c;在1978年發布。后續發…