【哇! C++】類和對象(三) - 構造函數和析構函數

????????

目錄

一、構造函數

1.1 構造函數的引入

1.2?構造函數的定義和語法

1.2.1 無參構造函數:

1.2.2 帶參構造函數

1.3?構造函數的特性

1.4 默認構造函數

二、析構函數

2.1 析構函數的概念

2.2 特性


????????如果一個類中什么成員都沒有,簡稱為空類。

????????空類中真的什么都沒有嗎?并不是,任何類在什么都不寫時,編譯器會自動生成以下6個默認成員函數。

????????默認成員函數用戶沒有顯式實現,編譯器會生成的成員函數稱為默認成員函數。

class Date
{};

一、構造函數

1.1 構造函數的引入

????????對于Date類,有如下程序:

#include<iostream>
using namespace std;class Date
{
public:void Init(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.Init(2025, 3, 5)return 0;
}

?????????對于Date類,可以通過Init公有方法給對象設置日期。但有時也會出現忘記Init初始化函數,而直接Push。為避免忘記,也為了方便程序撰寫,所以,C++規定了構造函數。

1.2?構造函數的定義和語法

????????構造函數是一種特殊的成員函數。雖然叫構造,但是其任務不是開空間,而是初始化對象。其特征如下:

  1. 構造函數名與類名相同;
  2. 無返回值,不需要寫void,void是空返回值;
  3. 對象實例化時編譯器自動調用對應的構造函數;
  4. 構造函數可以重載。

所以Date類構造函數可寫為:

1.2.1 無參構造函數:

#include<iostream>
using namespace std;class Date
{
public:    Date(){_year = 1;_month = 1;_day = 1;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();//Date d2();//err//Date d1(2024, 1, 27);//err,沒有與參數列表匹配的構造函數實例return 0;
}

運行結果為:?

????????此外,C++規定,無參構造函數變量名后不能加小括號。Date d2();有可能是函數的聲明,返回類型是Date,因為這個地方要寫函數聲明的話,小括號中是要加參數類型的。

1.2.2 帶參構造函數

#include<iostream>
using namespace std;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(2025, 3, 5);return 0;
}

????????構造函數可以函數重載,也可以改寫為全缺省。

#include<iostream>
using namespace std;class Date
{
public:Date(){_year = 1;_month = 1;_day = 1;}Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print{cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(2025, 3, 5);return 0;
}

????????語法上,上述兩個函數也可以同時存在,因為函數重載,函數名雖然相同,但參數不同。但是在調用Date d1;時,會產生歧義,編譯器不知道要調用誰,是要調用無參的還是要調用全缺省的。所以一般情況下,我們不這樣寫。

1.3?構造函數的特性

????????1.C++規定,對象定義(實例化)的時候,必須調用構造函數。

????????2.構造函數是默認成員函數,默認成員函數的特征是:我們沒有顯示定義,編譯器會自動生成一個無參的;如果寫了,編譯器就不會生成。

????????但是,當我們這樣寫如下代碼以后,編譯器調用了默認生成的構造函數,但是什么也沒干,沒有初始化。

#include<iostream>
using namespace std;class Date
{
public:void func(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year = 1;int _month = 1;int _day;
};int main()
{Date d1;d1.Print();//A _aa;return 0;
}

運行過程為:

運行結果為:

????????說明了使用編譯器實現的默認構造函數出來初始化的數據是隨機值,不是0。

????????C++98規定,默認生成的構造函數,對于內置類型不做處理;對于自定義類型會直接調用他的默認構造函數。即編譯器對生成默認了構造函數,對int不做處理,但對于自定義成員類型A aa;要調用A的構造函數。

????????內置類型/基本類型? ? ? ?-? ? ? ?int/char/double/指針

????????自定義類型? ? ? ? ? ? ? ? ? ?-? ? ? ?struct/class

????????C++11對這個語法進行補丁,在聲明的位置給缺省值。即不給缺省值,編譯器什么都不管;給缺省值,就默認生成了構造函數,用缺省值去完成初始化。在類中,默認了Date(){int _year = 1;int _month = 1;};

1.4 默認構造函數

#include<iostream>
using namespace std;class Date
{    
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year = 1;int _month = 1;int _day;
};int main()
{Date d1;return 0;
}

????????當我們運行時發現上述代碼報錯:此處編譯報錯,提示沒有默認構造函數可以用。

????????很多人經常理解默認構造函數就是編譯器生成的那一個。編譯器默認生成的構造函數是默認構造函數,但只是其中之一。

????????無參的構造函數全缺省構造函數也被稱為默認構造函數,且默認構造函數有且只能有一個。?一般情況下,建議優選全缺省構造函數。

總結:不需要傳參就可以調用的構造函數,都可以叫默認構造函數。

????????所以,上述代碼中,沒有無參,也沒有全缺省的默認構造函數,此時就需要編譯器就要生成一個默認構造函數。

????????但是編譯器默認生成的構造函數是有條件的,基于默認成員函數的特性:即沒有寫顯示定義的構造函數,編譯器才會自動生成一個無參的默認構造函數;一旦用戶顯示定義,編譯器就不會再生成。

? ? ? ? 為了使上述程序能夠通過,需要函數重載,顯式定義一個默認構造函數。

#include<iostream>
using namespace std;class Date
{    
public:Date(){_year = 1;_month = 1;_day = 1;}Date(int year, int month, int day){_year = year;_month = month;_day = day;}Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year = 1;int _month = 1;int _day;
};int main()
{Date d1;return 0;
}

二、析構函數

2.1 析構函數的概念

????????內存泄漏是不會報錯的,所以經常會忘記destory,所以C++就有了析構函數。

????????析構函數:與構造函數功能相反,析構函數不是完成對對象本身的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時會自動調用析構函數,完成對象中資源的清理工作。相當于destory,把動態開辟的數組空間free掉,不清理的話會出現內存泄漏。所以:構造函數完成的不是創建,析構函數完成的也不是銷毀。

????????在函數名前加~,在C語言中,~表示按位取反,所以選用這個符號就表示和構造函數的功能是相反的。

2.2 特性

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

  1. 析構函數名是類名前加字符“~”;
  2. 沒有參數也沒有返回值;
  3. 一個類只能有一個析構函數。若未顯式定義,系統會自動生成默認的析構函數。注意:析構函數不能重載;
  4. 對象生命周期結束時,C++編譯系統系統自動調用析構函數。

????????第4點類似于構造函數,構造函數在實例化的時候會自動調用。

#include<iostream>
using namespace std;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;
}

????????程序運行結束后輸出:~Time()。

????????在main方法中根本沒有直接創建Time類的對象,為什么最后會調用Time類的析構函數?

????????因為:main方法中創建了Date對象d,而d中包含4個成員變量,其中_year,_month,_day三個是內置類型成員,銷毀時不需要資源清理,最后系統直接將其內存回收即可;而_t是Time類對象,所以在d銷毀時,要將其內部包含的Time類的_t對象銷毀,所以要調用Time類的析構函數。

????????但是:main函數中不能直接調用Time類的析構函數,實際要釋放的是Date類對象,所以編譯器會調用Date類的析構函數,而Date沒有顯式提供,則編譯器會給Date類生成一個默認的析構函數,目的是在其內部調用Time類的析構函數,即當Date對象銷毀時,要保證其內部每個自定義對象都可以正確銷毀main函數中并沒有直接調用Time類析構函數,而是顯式調用編譯器為Date類生成的默認析構函數。

????????注意:創建哪個類的對象則調用該類的析構函數,銷毀那個類的對象則調用該類的析構函數。

????????如果類中沒有申請資源時,析構函數可以不寫,直接使用編譯器生成的默認析構函數,比如
Date類;有資源申請時,一定要寫,否則會造成資源泄漏,比如Stack類。

#include<iostream>
using namespace std;class Stack
{
public:    Stack(int capacity = 3){cout << "Stack(int capacity = 3)" << endl;_arry = (int*)malloc(capacity * sizeof(4));if(_arry == NULL){perror("malloc");}_capacity = capacity;}void Push(int x){_arry[_size] = x;_size++;}~Stack(){cout << "~Stack()" << endl;free(_arry);_arry = NULL;_size = 0;_capacity = 0;}private:int* _arry;int _capacity = 0;int _size = 0;
};//注意必須要有分號class MyQueue
{
private:Stack st1;Stack st2;int _size = 0;
};//注意必須要有分號int main()
{MyQueue q;return 0;
}

運行結果為:?

2.3 析構順序? ? ? ??

????????銷毀順序為:局部對象(后定義的先析構)->局部的靜態->全局對象(后定義的先析構)。程序證明如下:

class Date
{
public:Date(int year = 1){_year = year;}~Date(){cout << "~Date()->" << _year << endl;}
private:int _year ;int _month;int _day;
};void func()
{Date d3(3);static Date d4(4);
}Date d5(5);
static Date d6(6);int main()
{Date d1(1);Date d2(2);func();return 0;
}

????????static Date d3(3);為局部靜態,和上邊兩個的存儲區域不同,第3是存在靜態區的,雖然定義在了局部,但是生命周期是全局的。在main函數結束以后才會銷毀。所以在這之前要先把main函數中的局部變量先銷毀。

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

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

相關文章

【五.LangChain技術與應用】【11.LangChain少樣本案例模板:小數據下的AI訓練】

深夜的創業孵化器里,你盯著屏幕上的醫療AI項目,手里攥著僅有的97條標注數據——這是某三甲醫院心內科攢了三年的罕見病例。投資人剛剛發來最后通牒:“下周demo要是還分不清心肌炎和感冒,就撤資!” 這時你需要掌握的不是更多數據,而是讓每個樣本都變成會復制的孫悟空的毫毛…

2005-2019年各省城鎮人口數據

2005-2019年各省城鎮人口數據 1、時間&#xff1a;2005-2019年 2、來源&#xff1a;國家統計局、統計年鑒 3、指標&#xff1a;地區、年份、城鎮人口(萬人) 4、范圍&#xff1a;31省 5、指標解釋&#xff1a;?城鎮人口是指居住在城市、集鎮的人口&#xff0c;主要依據人群…

Anaconda 部署 DeepSeek

可以通過 Anaconda 環境部署 DeepSeek 模型&#xff0c;但需結合 PyTorch 或 TensorFlow 等深度學習框架&#xff0c;并手動配置依賴項。 一、Anaconda 部署 DeepSeek 1. 創建并激活 Conda 環境 conda create -n deepseek python3.10 # 推薦 Python 3.8-3.10 conda activate…

Python 面向對象高級編程-定制類

目錄 __str__ __iter__ __getitem__ __getattr__ __call__ 小結 看到類似__slots__這種形如__xxx__的變量或者函數名就要注意&#xff0c;這些在Python中是有特殊用途的。 __slots__我們已經知道怎么用了&#xff0c;__len__()方法我們也知道是為了能讓class作用于len()…

MCP與RAG:增強大型語言模型的兩種路徑

引言 近年來&#xff0c;大型語言模型&#xff08;LLM&#xff09;在自然語言處理任務中展現了令人印象深刻的能力。然而&#xff0c;這些模型的局限性&#xff0c;如知識過時、生成幻覺&#xff08;hallucination&#xff09;等問題&#xff0c;促使研究人員開發了多種增強技…

IDEA Generate POJOs.groovy 踩坑小計 | 生成實體 |groovy報錯

一、無法生成注釋或生成的注釋是null 問題可能的原因&#xff1a; 1.沒有從表里提取注釋信息&#xff0c;修改def calcFields(table)方法即可 def calcFields(table) {DasUtil.getColumns(table).reduce([]) { fields, col ->def spec Case.LOWER.apply(col.getDataType().…

ue5.5崩潰報gpu錯誤快速修復注冊表命令方法

網上已經有很多方法了&#xff0c;自己寫了個regedit比處理dos批處理命令&#xff0c;啟動時需要win 管理員身份拷貝后&#xff0c;將以下代碼&#xff0c;保存為 run.bat格式批處理文件&#xff0c;右鍵鼠標&#xff0c;在彈出菜單中&#xff0c;選擇用管理員身份運行。即可。…

能量石[算法題]

題目來源&#xff1a;第十五屆藍橋杯大賽軟件賽省賽Java 大學 B 組&#xff08;算法題&#xff09; 可以參考一下&#xff0c;本人也是比較菜 不喜勿噴&#xff0c;求求求 import java.util.Scanner;?public class Main {public static void main(String[] args) {Scanner s…

馬爾科夫不等式和切比雪夫不等式

前言 本文隸屬于專欄《機器學習數學通關指南》&#xff0c;該專欄為筆者原創&#xff0c;引用請注明來源&#xff0c;不足和錯誤之處請在評論區幫忙指出&#xff0c;謝謝&#xff01; 本專欄目錄結構和參考文獻請見《機器學習數學通關指南》 正文 統計概率的利劍&#xff1a;掌…

基于 STC89C52 的 8x8 點陣顯示漢字

一、引言 在電子信息顯示領域,漢字的直觀呈現為信息傳遞帶來極大便利。8x8 點陣雖顯示空間有限,但通過合理設計,能夠清晰展示一些常用、簡單的漢字,豐富電子設備的交互界面。STC89C52 單片機作為一款經典且應用廣泛的微控制器,以其成本低廉、易于開發的特性,成為驅動 8x…

二進制、八進制、十進制和十六進制間的轉換(原理及工程實現)

在計算機科學和編程中&#xff0c;進制轉換是一個非常重要的基礎知識。無論是二進制、八進制、十進制還是十六進制&#xff0c;它們在不同的場景中都有廣泛的應用。本文將詳細介紹常用進制之間的轉換方法&#xff0c;并附上C語言示例代碼&#xff0c;幫助大家更好地理解和掌握這…

從零開始的 Kafka 學習(二)| 集群啟動

1. 相關概念 1.1 代理&#xff1a;Broker 使用Kafka前&#xff0c;我們都會啟動Kafka服務進程&#xff0c;這里的Kafka服務進程我們一般會稱之為Kafka Broker 或 Kafka Server。因為Kafka是分布式消息系統所以再實際的生產環境中&#xff0c;是需要多個服務進程形成集群提供消…

python如何隨機產生一堆數字并輸出

python隨機產生一堆數字并輸出的方法&#xff1a; 通過for循環語句多次執行for循環里面的“random.randint()”函數產生隨機數。將產生的隨機數賦值給變量&#xff0c;輸出這個變量就可以了 執行結果如下&#xff1a;

vue3與react、 react hooks

一、Vue3新特性&#xff1a;setup、ref、reactive、computed、watch、watchEffect函數、生命周期鉤子、自定義hooks函數、toRef和toRefs、shallowReactive 與 shallowRef、readonly 與 shallowReadonly、toRaw 與 markRaw、customRef、provide 與 inject、Fragment、Teleport、…

《基于WebGPU的下一代科學可視化——告別WebGL性能桎梏》

引言&#xff1a;科學可視化的算力革命 當WebGL在2011年首次亮相時&#xff0c;它開啟了瀏覽器端3D渲染的新紀元。然而面對當今十億級粒子模擬、實時物理仿真和深度學習可視化需求&#xff0c;WebGL的架構瓶頸日益凸顯。WebGPU作為下一代Web圖形標準&#xff0c;通過顯存直存、…

寵物醫療對接DeepSeek詳細方案

基于DeepSeek本地化部署技術與醫療場景優化實踐 一、核心架構設計 1. 本地化部署與數據安全 私有化服務器部署:將DeepSeek模型部署在寵物醫院本地服務器,所有診療數據(如寵物病歷、影像報告)均存儲于院內,避免云端傳輸風險數據加密機制:采用AES-256加密算法對醫療數據加…

K8s 1.27.1 實戰系列(一)準備工作

一、主機規劃與硬件要求 1、節點數量 至少需要 3 臺服務器(1 臺 Master 節點,2 臺 Worker 節點)。本地測試可縮容:若僅用于測試,可縮減為 1 個 Master 和 1 個 Worker,但需注意穩定性風險。2、硬件配置 ?Master 節點:建議 2 核 CPU、8GB 內存、80GB 硬盤。?Worker 節…

2.PSCAD是什么軟件?

PSCAD&#xff08;Power Systems Computer Aided Design&#xff09;是一款功能強大的電力系統仿真軟件&#xff0c;廣泛應用于電力系統的建模、仿真和分析。它結合了電磁暫態仿真引擎EMTDC&#xff08;Electromagnetic Transients including DC&#xff09;&#xff0c;能夠精…

Stable Diffusion模型Pony系列模型深度解析

Stable Diffusion模型Pony系列模型深度解析 一、技術架構與核心特性 基于SDXL的深度優化 Pony系列模型以SDXL為基礎框架&#xff0c;通過針對二次元/動漫風格的微調&#xff0c;強化了在該領域的生成能力&#xff0c;同時保留了對寫實場景的兼容性?。其訓練數據特別側重于人…

FastGPT 引申:混合檢索完整實例

文章目錄 FastGPT 引申&#xff1a;混合檢索完整實例1. 各檢索方式的初始結果2. RRF合并過程3. 合并后的結果4. Rerank重排序后5. 最終RRF合并6. 內容總結 FastGPT 引申&#xff1a;混合檢索完整實例 下邊通過一個簡單的例子說明不同檢索方式的分值變化過程&#xff0c;假設我…