C++類與對象(二):六個默認構造函數(一)

在學C語言時,實現棧和隊列時容易忘記初始化和銷毀,就會造成內存泄漏。而在C++的類中我們忘記寫初始化和銷毀函數時,編譯器會自動生成構造函數和析構函數,對應的初始化和在對象生命周期結束時清理資源。那是什么是默認構造函數呢?例如在一個空類中,編譯器會自動生成六個默認函數。默認成員函數:用戶沒有顯式實現,編譯器會生成的成員函數稱為默認成員函數。

目錄

構造函數

構造函數的特性:

析構函數

拷貝構造函數


構造函數

概念:是一個特殊的成員函數,名字與類名相同,創建類類型對象時由編譯器自動調用,以保證 每個數據成員都有 一個合適的初始值,并且在對象整個生命周期內只調用一次。

構造函數的特性:

1. 函數名與類名相同。

2. 無返回值。

3. 對象實例化時編譯器自動調用對應的構造函數。

4. 構造函數可以重載。

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

7、無參的構造函數和全缺省的構造函數都稱為默認構造函數,并且默認構造函數只能有一個。 注意:無參構造函數、全缺省構造函數、我們沒寫編譯器默認生成的構造函數,都可以認為 是默認構造函數。

示例:

class Student {
public:Student(){cout << "Student()" << endl;}
private:int age;
};int main()
{Student s1;
}

運行結果:

?創建一個Student對象,我們并未調用初始化函數,編譯器自動調用了默認構造函數Student(),這個雖然是我們自己寫的,但是也是默認構造函數。

注意:無參的構造函數和全缺省函數都可以稱為默認構造函數,并且默認構造函數只能有一個。編譯器自動生成的也是一個默認構造函數,所以有三個默認構造函數。

那么在沒有寫構造函數下,編譯器自動生成的默認構造函數會對內置類型以及自定義類型初始化嗎?

示例:

class Stack {
private:int* _a;int _top;int _capacity;
};class Student {
public:Student(){cout << "Student()" << endl;}
private:int age;Stack s;
};int main()
{Student st1;return 0;
}

通過調試看一下編譯器自動生成的默認構造函數是否對?age和s初始化:

從這里可以看出都進行了初始化,其實不然,如果只有內置類型的話就不初始化了,小編用的是VS2019,編譯器不同是否初始化也不同,所以在寫代碼時不能依賴編譯器自動生成的默認構造函數,還是自己手動寫更好。

這是只用age變量時的結果?:

總結:編譯器自動生成的默認構造函數,對于內置類型不做處理 (但是我們可以在聲明時給值),而對于自定義類型會去調用它自己的默認構造函數。

所以一般情況下構造函數都需要我們自己寫,除非以下兩種情況:

1、 內置類型成員都有缺省值,且符合預期值。

2、全是自定義類型成員,且自定義類型成員都有構造函數。

析構函數

概念:與構造函數功能相反,析構函數不是完成對對象本身的銷毀,局部對象銷毀工作是由 編譯器完成的。而對象在銷毀時會自動調用析構函數,完成對象中資源的清理工作

析構函數特征:

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

2. 無參數無返回值類型。

3. 一個類只能有一個析構函數。若未顯式定義,系統會自動生成默認的析構函數。注意:析構 函數不能重載。

4. 對象生命周期結束時,C++編譯系統系統自動調用析構函數。

示例:

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

運行結果:

?這里都會自動調用析構函數來清理資源,那么問題來了,是每次都需要寫析構函數嗎?

析構函數就和之前對動態空間釋放一樣,對于內置類型變量并沒有處理,因為它們在棧上開辟的空間,在程序生命周期結束會自動銷毀,而向系統申請的空間不一樣,是開辟在堆上的,不能自動釋放,只能手動釋放空間,所以有以下三種情況:

1、一般情況下,有動態資源申請,就需要顯示寫析構函數。

2、沒有動態資源申請,不需要寫析構函數。

3、需要資源釋放的都是自定義成員,不要寫析構函數。

拷貝構造函數

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

如果形參是值傳遞,那么會產生什么結果?

示例:

class Student {
public:Student(int age = 18){cout << "Student()" << endl;_age = age;}Student(const Student s)//報錯{_age = s._age;}Student(const Student& s)//正確寫法{_age = s._age;}
private:int _age;
};int main()
{Student s1(20);Student s2(s1);return 0;
}

?這里會報錯,形成無窮遞歸,傳值調用時會先調用Student(Student s),因為傳值所以會再一次調用,循環往復,所以報錯了,可以通過一下示例來加深理解:

?這里進行調試,在準備進入test函數時觀察是否進入了test函數:

這里可以觀察到在準備進入test函數時卻進入Student函數,所以如果在Student函數的形參的傳遞是值傳遞,那么就會無窮遞歸。

?C++規定:內置類型可以直接拷貝,自定義類型必須調用拷貝構造完成拷貝

拷貝構造函數特征:

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

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

3. 若未顯式定義,編譯器會生成默認的拷貝構造函數。 默認的拷貝構造函數對象按內存存儲按 字節序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。

對于內置類型的拷貝可以不用寫拷貝構造函數,但是對于自定義類型需要自己寫拷貝構造函數?

示例:

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

這段代碼沒有寫拷貝構造函數,看看會出現什么結果:

?這是什么問題呢?看不出可以調試看一下:

通過調試可以看出,兩個對象的_a的地址相同,也就是說指向了同一塊空間,當指向同一塊空間時,會對該空間進行兩次析構,所以程序崩潰了。

這時就需要我們自己來寫拷貝構造函數,不可以依賴編譯器自動生成的拷貝構造函數。

正確代碼:

class Stack {
public:Stack(){cout << "Stack()" << endl;_a = (int*)malloc(sizeof(int) * 4);if (_a == nullptr){perror("malloc fail");return;}_capacity = 4;_top = 0;}~Stack(){cout << "~Stack" << endl;free(_a);_a = nullptr;_capacity = _top = 0;}Stack(const Stack& st){_a = (int*)malloc(sizeof(int) * st._top);if (_a == nullptr){perror("malloc fail");return;}_capacity = st._capacity;_top = st._top;}
private:int* _a;int _top;int _capacity;
};int main()
{Stack st1;Stack st2(st1);return 0;
}

運行結果:

?這就是自定義類型的深拷貝,當然深拷貝的知識不止這一點點,關注博主后續給你帶來C++更多知識。

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

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

相關文章

嵌入式培訓之數據結構學習(一)數據結構的基礎概念、線性表

一、基礎概念 1、數據結構&#xff1a;相互之間存在一種或多種特定關系的數據元素的集合。&#xff08;特定關系有邏輯關系與線性關系&#xff09; &#xff08;1&#xff09;邏輯結構 集合&#xff0c;所有數據在同一個集合中&#xff0c;關系平等&#xff08;數組&#xff…

Android Exoplayer 實現多個音視頻文件混合播放以及音軌切換

在之前的文章ExoPlayer中常見MediaSource子類的區別和使用場景中介紹了Exoplayer中各種子MediaSource的使用場景&#xff0c;這篇我們著重詳細介紹下實現多路流混合播放的用法。常見的使用場景有&#xff1a;視頻文件電影字幕、正片視頻廣告視頻、背景視頻背景音樂等。 初始化…

推特逆向算法,推特爬蟲,數據分析,推特關鍵詞搜索

祝大家五一假期快樂&#xff01; 最近推特加了逆向&#xff0c;頻繁出現404&#xff0c;無法正常抓取數據&#xff0c;這里給出推特逆向的思路及代碼&#xff0c;供大家參考學習&#xff01; 本文將介紹如何使用 Python 模擬請求 Twitter 的 GraphQL 接口&#xff0c;結合 re…

圖形化編程平臺的破局之道:從工具同質化到生態差異化

一、同質化困局的底層邏輯剖析 在全球圖形化編程市場中&#xff0c;工具功能趨同已成為行業共識。據 Statista 2024 年數據顯示&#xff0c;主流平臺的基礎功能重合度高達 78%&#xff0c;核心模塊&#xff08;如條件判斷、循環結構&#xff09;的實現方式高度相似。這種現象的…

【Rust】枚舉和模式匹配

目錄 枚舉和模式匹配枚舉的定義Option 枚舉控制流運算符 match簡潔控制流 if let 枚舉和模式匹配 枚舉的定義 結構體給予你將字段和數據聚合在一起的方法&#xff0c;像 Rectangle 結構體有 width 和 height 兩個字段。而枚舉給予你一個途徑去聲明某個值是一個集合中的一員。…

應急響應靶機——WhereIS?

用戶名及密碼&#xff1a;zgsf/zgsf 下載資源還有個解題.exe: 1、攻擊者的兩個ip地址 2、flag1和flag2 3、后門程序進程名稱 4、攻擊者的提權方式(輸入程序名稱即可) 之前的命令&#xff1a; 1、攻擊者的兩個ip地址 先獲得root權限&#xff0c;查看一下歷史命令記錄&#x…

變量函數實戰:高保真APP原型“發票頁面”動態交互教程

變量函數是高保真交互原型設計中常見的高級交互功能&#xff0c;能夠避免重復復制與手動修改頁面元素和邏輯標注&#xff0c;讓演示更有真實體驗感。本文分享一個高保真APP交互原型頁面的實操案例&#xff0c;結合原型設計工具中的變量函數與邏輯判斷功能&#xff0c;手把手教你…

量子加密通信:守護信息安全的未來之盾

摘要 在數字化時代&#xff0c;信息安全成為全球關注的焦點。傳統加密技術面臨著被量子計算破解的風險&#xff0c;而量子加密通信作為一種基于量子力學原理的新型加密技術&#xff0c;提供了理論上無條件安全的通信保障。本文將詳細介紹量子加密通信的基本原理、技術實現、應用…

《Vue.js》閱讀之響應式數據與副作用函數

Vue.js 《Vue.js設計與實現》&#xff08;霍春陽&#xff09; 適合&#xff1a;從零手寫Vue3響應式系統&#xff0c;大廠面試源碼題直接覆蓋。重點章節&#xff1a;第4章&#xff08;響應式&#xff09;、第5章&#xff08;渲染器&#xff09;、第8章&#xff08;編譯器&…

數據處理專題(十三)

學會基本的圖像處理技術。? OpenCV 基礎 實踐&#xff1a;使用 OpenCV 進行圖像讀取、顯示和基本處理? 03 代碼示例 1. 導入必要的庫 import cv2import numpy as npimport matplotlib.pyplot as plt 2. 圖像讀取 # 讀取圖像image_path path_to_your_image.jpg # 替換…

springboot旅游小程序-計算機畢業設計源碼76696

目 錄 摘要 1 緒論 1.1研究背景與意義 1.2研究現狀 1.3論文結構與章節安排 2 基于微信小程序旅游網站系統分析 2.1 可行性分析 2.1.1 技術可行性分析 2.1.2 經濟可行性分析 2.1.3 法律可行性分析 2.2 系統功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系統…

P1874 快速求和

目錄 題目算法標簽: 動態規劃, 線性 d p dp dp思路代碼 題目 P1874 快速求和 算法標簽: 動態規劃, 線性 d p dp dp 思路 求的是最少組成 n n n的加法次數, 對于當前數字序列可以設計狀態表示 f [ i ] [ j ] f[i][j] f[i][j]表示考慮前 i i i個字符, 并且和是 j j j的所有方…

知名人工智能AI培訓公開課內訓課程培訓師培訓老師專家咨詢顧問唐興通AI在金融零售制造業醫藥服務業創新實踐應用

AI賦能未來工作&#xff1a;引爆效率與價值創造的實戰營 AI驅動的工作革命&#xff1a;從效率提升到價值共創 培訓時長&#xff1a; 本課程不僅是AI工具的操作指南&#xff0c;更是面向未來的工作方式升級羅盤。旨在幫助學員系統掌握AI&#xff08;特別是生成式AI/大語言模型…

Linux 內核參數

文章目錄 什么是內核參數參數種類配置方式1. 編譯內核時配置2. 內核啟動時配置3. 內核運行時配置4. 加載內核模塊時配置總結 什么是內核參數 內核參數是 Linux 系統中用于控制和調整內核行為的可配置選項。這些參數影響系統的性能、安全性和各種功能特性。 參數種類 大部分參…

pythonocc 拉伸特征

micromamba install -c conda-forge pythonocc-core opencascade.js安裝不起來&#xff0c;ai用pythonocc練個手 拉伸線框 線成面 from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Vec from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire f…

Vue.js 頁面切換空白與刷新 404 問題深度解析

在使用 Vue.js 開發單頁應用 (SPA) 的過程中&#xff0c;開發者經常會遇到兩個常見問題&#xff1a;頁面切換時出現短暫的空白屏幕&#xff0c;以及刷新頁面時返回 404 錯誤。這兩個問題不僅影響用戶體驗&#xff0c;還可能阻礙項目的正常上線。本文將深入探討這兩個問題的成因…

Go 語言 slice(切片) 的使用

序言 在許多開發語言中&#xff0c;動態數組是必不可少的一個組成部分。在實際的開發中很少會使用到數組&#xff0c;因為對于數組的大小大多數情況下我們是不能事先就確定好的&#xff0c;所以他不夠靈活。動態數組通過提供自動擴容的機制&#xff0c;極大地提升了開發效率。這…

Qt5.14.2 鏈接 MySQL 8.4 遇到的問題

問題一: "Plugin caching_sha2_password could not be loaded: 找不到指定的模塊。 Library path is caching_sha2_password.dll QMYSQL: Unable to connect" 解決方法: alter user root@localhost identified with mysql_native_password by root;問題二: ERR…

Docker 部署 - Crawl4AI 文檔 (v0.5.x)

Docker 部署 - Crawl4AI 文檔 (v0.5.x) 快速入門 &#x1f680; 拉取并運行基礎版本&#xff1a; # 不帶安全性的基本運行 docker pull unclecode/crawl4ai:basic docker run -p 11235:11235 unclecode/crawl4ai:basic# 帶有 API 安全性啟用的運行 docker run -p 11235:1123…

開發工具分享: Web前端編碼常用的在線編譯器

1.OneCompiler 工具網址&#xff1a;https://onecompiler.com/ OneCompiler支持60多種編程語言&#xff0c;在全球有超過1280萬用戶&#xff0c;讓開發者可以輕易實現代碼的編寫、運行和共享。 OneCompiler的線上調試功能完全免費&#xff0c;對編程語言的覆蓋也很全&#x…