【C++】C++類和對象—(中)

前言:在上一篇類和對象(上)的文章中我們已經帶領大家認識了類的概念,定義以及對類和對象的一些基本操作,接下來我們要逐步進入到類和對象(中)的學習。我們將逐步的介紹類和對象的核心——類和對象的六個默認成員函數。(注意:這六個默認成員函數是類和對象的核心,學好了它我們才能更好的去理解類和對象!)

在這里插入圖片描述

MSTcheng: 個人主頁
個人專欄:
《C語言》
《數據結構》
《C++由淺入深》

在這里插入圖片描述

文章目錄

  • 一,什么是成員函數?
  • 二,默認成員函數的種類
  • 三,六個成員函數
    • 3.1構造函數
    • 3.2構造函數的種類和使用
  • 四,析構函數
    • 4.1析構函數的作用
    • 4.2析構函數的用法
  • 五,拷貝構造
    • 5.1拷貝構造的作用
    • 5.2拷貝構造的使用
  • 六,總結

一,什么是成員函數?

要學習類和對象中的六個成員函數,那我們就要先了解什么是成員函數?

  • 成員函數就是在類里面定義的函數,一般定義在類里面的都稱為成員如果是變量就稱為成員變量,如果是函數就稱為成員函數。
#include<iostream>
using namespace std;
class A
{
public://成員函數void func(){cout<<"void func()"<<endl;}
private://成員變量int _a;
}

二,默認成員函數的種類

C++的默認成員函數就是說我們沒有顯式的寫該函數編譯器會自動生成該函數就稱為默認成員函數。C++有六個默認的成員函數也就是說這六個成員函數如果我們自己不寫編譯器就會自動生成。至于為什么要搞這些默認成員函數待學完這些默認成員函數你自然就會明白!

六個默認成員函數如下:
在這里插入圖片描述

六個默認成員函數有三種,分別是執行初始化,拷貝,以及重載功能的函數。

  1. 執行初始化:構造函數,析構函數
  2. 執行拷貝:拷貝構造,賦值重載
  3. 取地址重載:兩個重載函數
    注意:這六個成員函數中比較重要的是前4個,后兩個可以作為了解!

下面我們依次介紹這幾個函數。

三,六個成員函數

3.1構造函數

構造函數的概念:構造函數是一種特殊的成員函數,用于在創建對象時初始化對象的狀態。通常與類名相同,無返回類型,支持重載。

3.2構造函數的種類和使用

在上面的構造函數中我們看到了幾種構造函數的類型分別是:

  1. 默認構造函數:無參數,如果我們沒有顯式的寫出來,編譯器就會自動生成并進行默認初始化。
  2. 帶參的構造函數:帶參的構造函數又分為有缺省值和沒有缺省值。注意全缺省的構造函數不能與無參的構造函數同時存在!因為這兩個函數在調用時會引發沖突!
  3. 拷貝構造函數,參數是類名這個我們后面介紹。
class Date
{
public:
//默認構造函數與類名相同,無返回值,支持重載//不帶參數Date(){_year = 1;_month = 1;_day = 1;}//Date(int year=1, int month=1, int day=1) 全缺省的構造函數//一般的構造函數Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << this->_year << "/" << this->_month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};

在這里插入圖片描述
什么都不寫自動調用編譯生成的默認構造,對成員變量進行默認初始化(值是隨機值).

通過上面的代碼我們能了解到構造函數的主要特點:

自動調用不顯式寫構造函數的情況下,對象創建時由編譯器隱式調用,無需手動觸發。
無返回值即使語法上不寫 void,也不實際返回任何值。
支持重載一個類可以定義多個參數列表不同的構造函數。

注意:對于自定義類型成員變量,要求調用這個成員變量的默認構造函數初始化。如果這個成員變量,沒有默認構造函數,那么就會報錯!這就要使用初始化列表了,初始化列表后面介紹。

class A
{
};
class Date
{
private:int _year;int _month;int _day;A a; //自定義類a 對于a的初始化就要去調用A這個類的默認構造!	
}

四,析構函數

4.1析構函數的作用

析構函數與構造函數相反,構造函數是執行初始化功能的那么析構函數就是釋放資源的。析構函數發揮作用的場景是在有資源需要釋放的時候使用,如果像日期類沒有資源就沒有必要使用析構。當然編譯器也會自動調用但不影響使用。

4.2析構函數的用法

析構函數相較于構造函數不同的是構造函數名與類名相同,而析構函數是~類名()
注意:若未顯式定義析構函數,編譯器會生成默認析構函數。
默認析構函數:
1. 對基本類型(如 int、float)無操作。
2. 對類成員調用其析構函數(按成員聲明順序逆序調用)。

class Date
{
public:
//構造函數Date(int year = 1, int month = 1, int day = 1){//在初始化之前先打印一下這個函數 這樣便于我們直觀的看到它在被調用cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;_year = year;_month = month;_day = day;}
//析構函數~Date(){//在釋放資源之前打印一下 方便直觀看到被調用cout << "~Date()" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;return 0;
}

在這里插入圖片描述通過上面的代碼我們可以認識到析構函數:

  1. 析構函數跟構造函數類似,無參數,無返回值。
  2. 自動調用析構函數,一個類只有一個析構若為顯式定義則調用編譯器生成的析構。
  3. 在同一個局部域中含有多個對象那么后定義的對象會先析構!

在上面的代碼中我們看到析構函數并沒有做什么事只是單純的在函數內部打印方便我們直觀看到調用,那這不就跟默認生成的析構一樣嗎?

像日期類這樣沒有資源的類編譯器默認生成的就夠用它不hi對內置類型如(int,float)做處理,但是如果是像棧這樣的類那么編譯器生成的析構就不能滿足我們的需求了。下面我們來看棧這個類:

class Stack
{
public:Stack(int n = 4){cout << "Stack(int n = 4)" << endl;_a = (int*)malloc(sizeof(int) * n);if (nullptr == _a){perror("malloc申請空間失敗");return;}_capacity = n;_top = 0;}//編譯器默認生成的析構函數不能滿足我們的要求它不會去自動的釋放資源 所以需要我們顯式寫析構函數~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_capacity = _top = 0;}
private:int* _a;size_t _capacity;size_t _top;
};

在這里插入圖片描述

總結一下就是:在對象生命周期結束時系統就會自動調用析構。析構函數與構造函數類似對內置類型不做處理,對于自定義類型的成員就調用它的析構,且無論我們是否顯式寫析構只要類里面包含自定義類型的成員那么就會去調用它自己那個類的析構!

五,拷貝構造

5.1拷貝構造的作用

拷貝構造的作用就是使用同類型的對象去初始化創建另外一個對象,其中這兩個對象都具有相同的成員變量值。可以將拷貝構造理解為給對象創建副本。

5.2拷貝構造的使用

  1. 拷貝構造與構造函數類似,就是參數上略有不同,所以拷貝構造是構造函數的一個重載。
  2. 如果沒有顯示定義拷貝構造,編譯器就會自動生成一個拷貝構造。編譯器生成的拷貝構造對內置類型會進行淺拷貝,對于自定義類型就去調用它的拷貝構造。
  3. C++規定了只要是自定義類型的對象進行拷貝行為就要去調用拷貝構造,無論是自定義類型的傳值傳參還是傳值返回都要去調用拷貝構造。對于引用返回可能引發的野引用問題可以去看我之前的文章:傳送門:引用返回的坑
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;_year = year;_month = month;_day = day;}//d2(d1) 拷貝構造函數生成對象的拷貝 參數類型與被拷貝對象的類型相同為DateDate(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//這里拷貝構造其實也可以傳指針 引用的本質其實就是指針 但是指針還需要開空間 而引用不需要開空間//所以還是優先使用引用做為函數參數/*Date(Date* d){_year = d->_year;_month = d->_month;_day = d->_day;}*/~Date(){cout << "~Date()" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2025, 4, 24);  // 構造Date d2(d1);           // 拷貝構造 構成 副本(原對象)//直接賦值也是拷貝的意思Date d4 = d1;          // 拷貝構造//使用指針 不推薦//Date d3(&d1);		   // 構造//Date d5 = &d1;	   // 構造return 0;
}

在上面的拷貝構造中參數一定要是傳引用傳參而不是傳值傳參,傳值傳參就會引發無窮遞歸!下面我們畫圖來解釋:
在這里插入圖片描述

這里要注意:像日期類內部沒有資源我們可以使用編譯器默認生成的拷貝構造就可以滿足我們的要求;但是像棧這樣的類就不一樣了,棧這樣的類內部有資源如果直接淺拷貝就會有問題,所以要自己寫拷貝構造下面我們就來了解一下深淺拷貝問題:

class Stack
{
public://構造函數Stack(int n = 4){_a = (int*)malloc(sizeof(int) * n);if (nullptr == _a){perror("malloc申請空間失敗");return;}_capacity = n;_top = 0;}// st2(st1) 拷貝構造函數生成對象的拷貝 參數類型與被拷貝對象的類型相同為stckStack(const Stack& s){cout << "Stack(Stack& s)" << endl;_a = (int*)malloc(sizeof(int) * s._capacity);if (nullptr == _a){perror("malloc申請空間失敗");return;}memcpy(_a, s._a, sizeof(int) * s._top);_top = s._top;_capacity = s._capacity;}
private:int* _a;size_t _capacity;size_t _top;
};

在這里插入圖片描述

這時可能有人問那以后是不是看到成員變量帶有指針的就要去寫拷貝構造呢?其實不是寫不寫拷貝構造其實跟寫析構函數一樣看類里面有沒有資源,一般來說有資源就要寫析構和拷貝構造,所以我們也可以看一個類如果顯式寫了析構函數那么就要寫拷貝構造。

六,總結

學完了上面的內容回答下面兩個問題:
第?:我們不寫時,編譯器默認生成的函數行為是什么,是否滿足我們的需求?

  • 當我們不寫時編譯器會自動生成調用對應的構造,析構,拷貝構造等函數。如果像日期類這樣沒有資源的類可以使用編譯器自己生成的構造,析構,拷貝構造函數;相反如果有資源則需要我們自己顯式寫對應的函數!

第?:編譯器默認生成的函數不滿足我們的需求,我們需要自己實現,那么如何自己實現?

  • 像有資源的類編譯器生成的函數不能滿足時比如像構造函數就要自己去創造空間,析構函數就要手動去釋放空間,拷貝構造就要完成深拷貝等。
以上就是本篇文章的所有內容了,感謝各位大佬觀看,制作不易還望各位大佬點贊支持一下!

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

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

相關文章

使用python-fastApi框架開發一個學校宿舍管理系統-前后端分離項目

今天給大家分享一個我最近做的一個學校宿舍管理系統&#xff0c;python版&#xff0c;這個系統實現的功能有&#xff1a;首頁 | 學校管理 | 宿舍樓管理 | 宿舍管理 | 學生管理 | 學生調宿 | 學生退宿 | 報修等級 | 宿舍衛生評分 | 違紀記錄 | 管理員管理 。一共有11個菜單。 使…

阻塞 vs 非阻塞:程序等待的兩種哲學

當程序需要等待外部操作時&#xff0c;是應該"干等"還是"邊等邊干"&#xff1f;為什么有些程序會卡住不動&#xff0c;而另一些卻能流暢運行&#xff1f;這一切都取決于阻塞與非阻塞的編程選擇&#xff01;本文將為你揭示這兩種模式的本質區別&#xff01;…

MySQL 核心操作全解析(用戶 + SHOW+DML+DCL)

MySQL 核心操作全解析&#xff08;用戶 SHOWDMLDCL&#xff09; 基于你提供的實操筆記&#xff0c;我們將 MySQL 核心操作拆解為用戶管理、SHOW 查詢命令、DML 數據操作、TRUNCATE 與 DELETE 對比、DCL 權限控制五大模塊&#xff0c;梳理語法邏輯、補充避坑提示&#xff0c;幫…

多語言編碼Agent解決方案(6)-部署和使用指南

部署和使用指南 本指南提供完整的部署和使用說明&#xff0c;幫助您設置后端服務并在VSCode、Eclipse和IntelliJ中使用相應的插件。這個解決方案基于vLLM提供AI編碼輔助&#xff0c;支持英語、中文和日文。 前提條件 操作系統&#xff1a;Linux、macOS或Windows&#xff08;推薦…

濾波器的三重境界:從信號處理到自動駕駛測試的基石

在自動駕駛的宏大敘事中&#xff0c;我們常常聚焦于人工智能、深度學習、高精地圖等"明星技術"。然而&#xff0c;在這些耀眼的光環背后&#xff0c;有一個低調卻至關重要的"幕后英雄"——濾波器。它不僅是信號處理的工具&#xff0c;更是連接物理世界與數…

Part4.第8章:神經網絡

第8章 激活函數 如果沒有激活函數&#xff0c;不論幾層的神經網絡都是一個線性回歸。激活函數的作用是引入非線性。

nextjs+shadcn+tailwindcss實現博客中的overview

最近在用nextjsshadcntailwindcss練手&#xff0c;實現一個博客。做到了overView這里&#xff0c;可實現如下效果1.首先要安裝tailwindcss&#xff0c;這個在創建項目的時候就安裝了。2.然后安裝shadcn,官網教程&#xff1a;3.代碼如下&#xff1a;import {Card,CardContent } …

Kotlin 高階語法解析

Kotlin 高級語法深度解析1. 協程&#xff08;Coroutines&#xff09;1.1 基礎概念1.掛起和恢復2.協程構建器 (Coroutine Builders)3.協程作用域4.調度器1.2 核心用法1.3 實戰示例2. 密封類&#xff08;Sealed Classes&#xff09;2.1 定義與特性2.2 模式匹配2.3 應用場景3. 內聯…

9 基于機器學習進行遙感影像參數反演-以隨機森林為例

目錄 1 讀取數據 2 數據預處理 3模型訓練 4模型預測 5精度分析 由于回歸任務的標簽數據獲取比較困難,我們這次用水體指數NDWI來模擬作為回歸任務的標簽,通過隨機森林來擬合回歸NDWI,其計算公式如下: NDWI = (band3 - band5) / (band3 + band5) 實際情況下需要回歸的數…

C++多線程編程:跨線程操作全解析

C中的"線程"通常指單個執行流&#xff08;如std::thread對象&#xff09;&#xff0c;而"多線程"指程序中同時存在多個這樣的執行流&#xff0c;并涉及它們的創建、管理和同步。實現跨線程操作的核心在于安全地處理共享數據和線程間通信。 以下是實現跨線程…

【腦電分析系列】第13篇:腦電源定位:從頭皮到大腦深處,EEG源定位的原理、算法與可視化

前言腦電信號&#xff08;Electroencephalography, EEG&#xff09;是一種非侵入性的神經成像技術&#xff0c;能夠實時捕捉大腦的電活動。然而&#xff0c;頭皮上記錄到的信號是腦源活動經過頭皮、顱骨等介質“模糊”后的投影。想要從這些頭皮EEG信號追溯到大腦深處的電活動&a…

MySQL知識筆記

DATE_ADD(date,INTERVAL expr type) date 參數是合法的日期表達式。expr 參數是您希望添加的時間間隔。多查官方手冊&#xff01;&#xff01;命令行啟動和停止sql服務net start 數據庫名&#xff1b; 這是啟動服務命令&#xff1b; 例如&#xff1a;net start Mysql56…

2025算法八股——深度學習——MHA MQA GQA

MHA、MQA、GQA 都是深度學習中注意力機制的相關概念&#xff0c;其中 MHA 是標準的多頭注意力機制&#xff0c;MQA 和 GQA 則是其優化變體&#xff0c;以下是它們的區別、優缺點介紹&#xff1a;區別MHA&#xff08;多頭注意力&#xff09;&#xff1a;是 Transformer 架構的核…

Vue3》》eslint Prettier husky

安裝必要的依賴 npm install -D eslint eslint/js vue/eslint-config-prettier prettier eslint-plugin-vue 初始化 ESLint 配置 npm init eslint/config// eslint.config.js // 針對 JavaScript 的 ESLint 配置和規則。保持 JavaScript 代碼的一致性和質量 import js from &qu…

Custom SRP - Point and Spot Lights

https://catlikecoding.com/unity/tutorials/custom-srp/point-and-spot-lights/Lights with Limited Influence1 Point Lights1.1 Other Light Data (Point )同方向光一樣,我們支持有限數量的 Other Light.盡管場景中可能有很多 Other Lights,可能有超過光源上限的光源時可見的…

hive數據倉庫的搭建

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄前言一、內嵌模式二、本地模式三、遠程模式前言 HIVE是基于HDFS的數據倉庫&#xff0c;要首先搭建好HADOOP的集群才可以正常使用HIVE&#xff0c;HADOOP集運搭建詳見…

域名SSL證書免費申請lcjmSSL

.-.lcjmSSL&#xff08;又名“來此加密”&#xff09;是一個提供免費SSL證書申請的一站式平臺。它支持單域名、多域名以及泛域名證書申請&#xff0c;且單張證書最高可覆蓋100個域名&#xff0c;讓您輕松實現全站HTTPS加密。為什么您的網站必須安裝SSL證書&#xff1f;數據加密…

“能量逆流泵”:一種基于電容陣與開關矩陣的超高效大功率降壓架構

摘要本文提出并驗證了一種面向大功率降壓應用的革命性電源架構——"能量逆流泵"&#xff08;Energy Inversion Pump, EIP&#xff09;。該架構摒棄了傳統Buck轉換器中的電感元件&#xff0c;通過高速開關矩陣控制的電容陣列&#xff0c;將高壓側能量以"分時、分…

打造精簡高效的 uni-app 網絡請求工具

在 uni-app 開發中&#xff0c;網絡請求是連接前端與后端的核心橋梁。一個設計良好的請求工具能夠顯著提升開發效率&#xff0c;減少重復代碼。本文將分享一個精簡版的 uni-app 網絡請求工具實現&#xff0c;它保留了核心功能同時保持了足夠的靈活性。設計思路一個優秀的網絡請…

【面試場景題】交易流水表高qps寫入會有鎖等待或死鎖問題嗎

文章目錄一、先明確交易流水表的核心特性二、InnoDB的鎖機制在流水表寫入場景的表現1. 行鎖&#xff08;Record Lock&#xff09;&#xff1a;基本不涉及2. 間隙鎖&#xff08;Gap Lock&#xff09;與Next-Key Lock&#xff1a;幾乎不觸發3. 表鎖&#xff1a;僅在極端場景出現三…