九、重學C++—類和函數

上一章節:

八、重學C++—動態多態(運行期)-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147004745?spm=1001.2014.3001.5502

本章節代碼:

cpp/cppClassAndFunc.cpp · CuiQingCheng/cppstudy - 碼云 - 開源中國https://gitee.com/cuiqingcheng/cppstudy/blob/master/cpp/cppClassAndFunc.cpp

一、引言

????????學到這里,會深深被C++的靈活多變所折服,學習C++的過程仿佛遨游在瑰麗多彩的海底世界。類與函數便是其中極為精妙的招式。今天,就讓我們一起重新踏上探索 C++ 類與函數的奇妙之旅,揭開它們神秘的面紗。就像古人云:“溫故而知新,可以為師矣。” 重學 C++ 的類與函數,也能讓我們對編程有全新的感悟。

二、重新認識類:類中成員和特殊類

1、內聯函數:代碼中的“瞬移大師“

????????內聯函數,可以是類中的,也可以是普通函數。在常見的函數調用中,程序需要跳轉去執行函數代碼,執行完再跳轉回來,這中間會消耗一些時間和資源。而內聯函數呢,編譯器會直接將函數代碼嵌入到調用它的地方,因此這里常與宏函數對比

例如:

/***  1、內聯函數*/
#include <iostream>// 宏函數
# define ADD(a,b)  (a+b)// 內聯函數
inline int add(int& a, int &b)
{return a+b;
}class optData{
public:// 類中內聯函數inline int add(int& a, int &b){return a+b;}
};int main()
{int n = 5;int m = 13;std::cout << "sum1: " << add(n,m) << std::endl;std::cout << "sum2: " << ADD(n,m) << std::endl;optData opt;std::cout << "sum3: " << opt.add(n,m) << std::endl;return 0;
}

宏函數不推薦使用,宏函數在設計初,就存在以下缺點,(1)、類型不安全,無法進行類型檢測(2)、無法調試(3)、無法進行遞歸調用(4)、可讀性差。

使用場景:

(1)、短小且頻繁調用的函數:當函數體代碼量很少(通常不超過 3 - 5 行 ),且在程序中會被頻繁調用時,適合定義為內聯函數。

(2)、?模板函數:簡短的模板函數在編譯時會生成具體的函數實例,更容易被內聯化。內聯后的模板函數能提供更好的性能

#include <iostream>// 模板內聯函數,返回兩個數中較大的值
template <typename T>
inline T max(T a, T b) {return a > b? a : b;
}int main()
{int n = 5;int m = 13;int iMax = max(n, m);std::cout << "iMax: " << iMax << std::endl;return 0;
}

優點:

????????減少函數調用開銷;提高程序執行效率;增強代碼可讀性;類型安全檢查;相比于宏函數方便可調式

2、靜態成員:不依賴對象存在,是類中的”常駐大使“

????????靜態成員變量是類的所有對象共享的一個變量,它就像班級里的公共財產,不管哪個同學都可以使用它

例如:

/***  1、靜態成員*/#include <iostream>class Student {
public:Student(std::string name) :m_name(name){++m_totalStudents;}~Student() {--m_totalStudents;}// 靜態成員函數static int getTotalStudents() {// ++m_totalStudents; 錯誤靜態成員函數中不能出現普通成員變量,這里僅能操作靜態成員變量;return m_totalStudents;}static std::string getSchoolName(){return m_schoolName;}// 普通成員函數int getStudentsCount(){return getTotalStudents();}
private:std::string m_name;// 靜態成員變量static std::string m_schoolName;static int m_totalStudents;
};std::string Student::m_schoolName = "上海中學";
int Student::m_totalStudents = 0;int main()
{// 靜態成員Student stu1("小明");Student stu2("小紅");std::cout << "學生總數:" << Student::getTotalStudents() << " 學校名:"<< Student::getSchoolName()<<std::endl;std::cout << "小明知道的學生總數:" << stu1.getStudentsCount() << std::endl;return 0;
}

注意:

(1)靜態成員函數只能操作靜態成員變量;

(2)靜態成員屬于整個類共有的,不依賴于類所創建的對象;

(3)普通成員函數可以修改靜態成員變量,因為要注意線程安全;

3、const常量

3.1 、成員變量是常量

一經初始化便不能修改;

3.2、成員函數形參為常量

傳入形參在代碼段內不能修改;

3.3、成員函數返回值為常量

3.4、成員函數,后接const修飾

不能修改成員變量值;

例如:

#include <iostream>
class Student {
public:Student(std::string name) :m_name(name){++m_totalStudents;}Student(std::string name, std::string strlocal) : m_name(name),m_strLocal(strlocal){++m_totalStudents;}~Student() {--m_totalStudents;}// 靜態成員函數static int getTotalStudents() {// ++m_totalStudents; 錯誤靜態成員函數中不能出現普通成員變量,這里僅能操作靜態成員變量;return m_totalStudents;}static std::string getSchoolName(){return m_schoolName;}// 普通成員函數int getStudentsCount(){return getTotalStudents();}std::string getSchoolLocation(){return m_strLocal;}void setSex(const std::string strSex){// 傳入的形參不能修改;m_strSex = strSex;}const std::string getSex(){return m_strSex;}// 不能修改所有成員變量void getStudetCount(int &count) const{count = m_totalStudents;}private:const std::string m_strLocal{"上海"};std::string m_name;std::string m_strSex;// 靜態成員變量static std::string m_schoolName;static int m_totalStudents;
};std::string Student::m_schoolName = "上海中學";
int Student::m_totalStudents = 0;
int main()
{//constStudent stu1("小王");stu1.setSex("男");Student stu2("小麗");stu2.setSex("女");Student stu3("小張", "北京");stu3.setSex("男");int stuCount = 0;stu2.getStudetCount(stuCount);std::cout << "小王學校在哪兒:" << stu1.getSchoolLocation() << " 小王性別:" << stu1.getSex() << std::endl;std::cout << "小麗學校在哪兒:" << stu2.getSchoolLocation() << " 小麗學校學生數量:" << stuCount <<std::endl;std::cout << "小張學校在哪兒:" << stu3.getSchoolLocation() << std::endl;return 0;
}

4、無法實例化對象的類

4.1、抽象類無法實例化對象(略)

4.2、構造函數為私有的

// 構造函數私有
class baseClass {
private:baseClass(){std::cout << "構造函數" <<std::endl;}private:int m_num;
};

5、無法被繼承的類final

class NonInheritable2 final {
public:void print() {std::cout << "This is a final class." << std::endl;}
};

6、delete特殊用法(修飾構造函數)

在 C++ 里,在構造函數后面使用?= delete?是 C++11 引入的特性,其作用是顯式地刪除該構造函數。刪除構造函數后,就無法再使用該構造函數來創建類的對象,這在一些場景下很有用,下面詳細介紹:

6.1、禁止默認構造函數

當你不希望類擁有默認構造函數(即無參數的構造函數)時,可使用?= delete?將其刪除。

#include <iostream>class MyClass {
public:MyClass(int value) : data(value) {}// 刪除默認構造函數MyClass() = delete; 
private:int data;
};int main() {// MyClass obj; // 錯誤,默認構造函數已被刪除MyClass obj(42); // 正確,使用帶參數的構造函數return 0;
}

在上述代碼中,MyClass的默認構造函數被刪除,所以不能通過無參數方式構造對象;

6.2、禁止拷貝構造函數和拷貝賦值運算符

若你不希望類的對象被復制,可使用?= delete?刪除拷貝構造函數和拷貝賦值運算符。

#include <iostream>class NonCopyable {
public:NonCopyable() = default;// 刪除拷貝構造函數NonCopyable(const NonCopyable&) = delete; // 刪除拷貝賦值運算符NonCopyable& operator=(const NonCopyable&) = delete; 
};int main() {NonCopyable obj1;// NonCopyable obj2 = obj1; // 錯誤,拷貝構造函數已被刪除// NonCopyable obj3;// obj3 = obj1; // 錯誤,拷貝賦值運算符已被刪除return 0;
}

此代碼中,NonCopyable?類的拷貝構造函數和拷貝賦值運算符都被刪除,這就阻止了對象的復制操作。

三、友元

友元就像是類的 “好朋友”,雖然不在類的內部,但卻能訪問類的私有成員。它打破了類的封裝性,但有時候為了提高代碼的靈活性和效率,這種 “破格” 也是必要的

比如:

#include <iostream>class A {
public:A(int data) : m_privateData(data) {}protected:double m_protectedData{3.88};private:friend void friendFunction(A& a); // 友元函數friend class ClassB; // 友元類private:int m_privateData;
};void friendFunction(A& a) {std::cout << "訪問到私有數據:" << a.m_privateData << std::endl;
}class ClassB {
public:void accessClassAData(A& obj) {// 友元類可以訪問 ClassA 的私有和受保護成員std::cout << "Accessing private data of Class A: " << obj.m_privateData << std::endl;std::cout << "Accessing protected data of Class A: " << obj.m_protectedData << std::endl;}
};int main()
{// 友元A a(10);friendFunction(a);ClassB b;b.accessClassAData(a);
}

在上述代碼中,ClassB?被聲明為?A?的友元類,所以?ClassB?的成員函數?accessClassAData?能夠訪問?A?的私有成員?privateData?和受保護成員?protectedData。

使用場景

(1)、數據共享:當兩個類之間存在緊密的關聯,需要共享數據時,可以使用友元類。

注意事項

(1)、打破封裝性:友元類破壞了類的封裝性,因為它允許外部類訪問本類的私有和受保護成員。過度使用友元類會導致代碼的安全性和可維護性降低,所以應該謹慎使用。

(2)、單向性:友元關系是單向的。

(3)、不具有傳遞性。

四、名字空間

名字空間就像是編程世界里的 “房間分隔器”。當我們的項目越來越大,代碼中的名字(變量名、函數名、類名等)可能會產生沖突,這時候名字空間就能把不同功能的代碼隔離開來。

namespace Math {int add(int a, int b) {return a + b;}
}namespace Utility {int add(int a, int b) {return a * b;}
}int main() {std::cout << "Math 名字空間的加法:" << Math::add(3, 5) << std::endl;std::cout << "Utility 名字空間的加法:" << Utility::add(3, 5) << std::endl;return 0;
}

這里定義了?Math?和?Utility?兩個名字空間,它們都有?add?函數,但功能不同,通過名字空間的限定,我們可以準確調用到想要的函數。

五、總結

????????C++ 的類與函數蘊含著無盡的奧秘,從內聯函數的高效執行,到靜態成員的獨特共享機制,再到各種特殊類和關鍵字的巧妙運用,以及友元和名字空間的神奇功能,每一處都值得我們細細品味。

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

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

相關文章

lua和C的交互

1.C調用lua例子 #include <iostream> #include <lua.hpp>int main() {//用于創建一個新的lua虛擬機lua_State* L luaL_newstate();luaL_openlibs(L);//打開標準庫/*if (luaL_dofile(L, "test.lua") ! LUA_OK) {std::cerr << "Lua error: &…

java高并發------守護線程Daemon Thread

文章目錄 1.概念2.生命周期與行為2. 應用場景3. 示例代碼4. 注意事項 1.概念 Daemon &#xff1a; 滴門 在Java中&#xff0c;線程分為兩類&#xff1a;用戶線程(User Thread)和守護線程(Daemon Thread)。 守護線程是后臺線程&#xff0c;主要服務于用戶線程&#xff0c;當所…

Docker存儲策略深度解析:臨時文件 vs 持久化存儲選型指南

Docker存儲策略深度解析&#xff1a;臨時文件 vs 持久化存儲選型指南 一、存儲類型全景對比二、臨時存儲適用場景與風險2.1 最佳使用案例2.2 風險警示 三、持久化存儲技術選型3.1 Volume核心優勢Volume管理命令&#xff1a; 3.2 Bind Mount適用邊界掛載模式對比&#xff1a; 四…

【Linux網絡#18】:深入理解select多路轉接:傳統I/O復用的基石

&#x1f4c3;個人主頁&#xff1a;island1314 &#x1f525;個人專欄&#xff1a;Linux—登神長階 目錄 一、前言&#xff1a;&#x1f525; I/O 多路轉接 為什么需要I/O多路轉接&#xff1f; 二、I/O 多路轉接之 select 1. 初識 select2. select 函數原型2.1 關于 fd_set 結…

高級:微服務架構面試題全攻略

一、引言 在現代軟件開發中&#xff0c;微服務架構被廣泛應用于構建復雜、可擴展的應用程序。面試官通過相關問題&#xff0c;考察候選人對微服務架構的理解、拆分原則的掌握、服務治理的能力以及API網關的運用等。本文將深入剖析微服務架構相關的面試題&#xff0c;結合實際開…

使用MQTTX軟件連接阿里云

使用MQTTX軟件連接阿里云 MQTTX軟件阿里云配置MQTTX軟件設置 MQTTX軟件 阿里云配置 ESP8266連接阿里云這篇文章里有詳細的創建過程&#xff0c;這里就不再重復了&#xff0c;需要的可以點擊了解一下。 MQTTX軟件設置 打開軟件之后&#xff0c;首先點擊添加進行創建。 在阿…

【HFP】藍牙Hands-Free Profile(HFP)核心技術解析

藍牙 Hands-Free Profile&#xff08;HFP&#xff09;作為車載通信和藍牙耳機的核心協議&#xff0c;定義了設備間語音交互的標準化流程&#xff0c;并持續推動著無線語音交互體驗的革新。自2002年首次納入藍牙核心規范以來&#xff0c;HFP歷經多次版本迭代&#xff08;最新為v…

輕量化大模型微調工具XTuner指令微調實戰(下篇)

接著上篇文章《輕量化大模型微調工具XTuner指令微調實戰&#xff08;上篇&#xff09;》來接著寫教程。 一、模型轉換 模型訓練后會自動保存成 PTH 模型&#xff08;例如 iter_500.pth&#xff09;&#xff0c;我們需要利用 xtuner convert pth_to_hf 將其轉換為 HuggingFace…

pyTorch框架使用CNN進行手寫數字識別

目錄 1.導包 2.torchvision數據處理的方法 3.下載加載手寫數字的訓練數據集 4.下載加載手寫數字的測試數據集 5. 將訓練數據與測試數據 轉換成dataloader 6.轉成迭代器取數據 7.創建模型 8. 把model拷到GPU上面去 9. 定義損失函數 10. 定義優化器 11. 定義訓練…

強化學習課程:stanford_cs234 學習筆記(3)introduction to RL

文章目錄 前言7 markov 實踐7.1 markov 過程再敘7.2 markov 獎勵過程 MRP&#xff08;markov reward process&#xff09;7.3 markov 價值函數與貝爾曼方程7.4 markov 決策過程MDP&#xff08;markov decision process&#xff09;的 狀態價值函數7.4.1 狀態價值函數7.4.2 狀態…

操作系統 4.5-文件使用磁盤的實現

通過文件進行磁盤操作入口 // 在fs/read_write.c中 int sys_write(int fd, const char* buf, int count) {struct file *file current->filp[fd];struct m_inode *inode file->inode;if (S_ISREG(inode->i_mode))return file_write(inode, file, buf, count); } 進程…

libreoffice-help-common` 的版本(`24.8.5`)與官方源要求的版本(`24.2.7`)不一致

出現此錯誤的原因主要是軟件包依賴沖突&#xff0c;具體分析如下&#xff1a; ### 主要原因 1. **軟件源版本不匹配&#xff08;國內和官方服務器版本有差距&#xff09; 系統中可能啟用了第三方軟件源&#xff08;如 PPA 或 backports 源&#xff09;&#xff0c;導致 lib…

使用Geotools中的原始方法來操作PostGIS空間數據庫

目錄 前言 一、原生PostGIS連接介紹 1、連接參數說明 2、創建DataStore 二、工程實戰 1、Maven Pom.xml定義 2、空間數據庫表 3、讀取空間表的數據 三、總結 前言 在當今數字化與信息化飛速發展的時代&#xff0c;空間數據的處理與分析已成為眾多領域不可或缺的一環。從…

訊飛語音合成(流式版)語音專業版高質量的分析

一、引言 在現代的 Web 應用開發中&#xff0c;語音合成技術為用戶提供了更加便捷和人性化的交互體驗。訊飛語音合成&#xff08;流式版&#xff09;以其高效、穩定的性能&#xff0c;成為了眾多開發者的首選。本文將詳細介紹在 Home.vue 文件中實現訊飛語音合成&#xff08;流…

走進未來的交互世界:下一代HMI設計趨勢解析

在科技日新月異的今天&#xff0c;人機交互界面&#xff08;HMI&#xff09;設計正以前所未有的速度發展&#xff0c;不斷引領著未來的交互世界。從簡單的按鈕和圖標&#xff0c;到如今的智能助手和虛擬現實&#xff0c;HMI設計不僅改變了我們的生活方式&#xff0c;還深刻影響…

洛谷題單3-P1217 [USACO1.5] 回文質數 Prime Palindromes-python-流程圖重構

題目描述 因為 151 151 151 既是一個質數又是一個回文數&#xff08;從左到右和從右到左是看一樣的&#xff09;&#xff0c;所以 151 151 151 是回文質數。 寫一個程序來找出范圍 [ a , b ] ( 5 ≤ a < b ≤ 100 , 000 , 000 ) [a,b] (5 \le a < b \le 100,000,000…

學習筆記,DbContext context 對象是保存了所有用戶對象嗎

DbContext 并不會將所有用戶對象保存在內存中&#xff1a; DbContext 是 Entity Framework Core (EF Core) 的數據庫上下文&#xff0c;它是一個數據庫訪問的抽象層它實際上是與數據庫的一個連接會話&#xff0c;而不是數據的內存緩存當您通過 _context.Users 查詢數據時&…

本地命令行啟動服務并連接MySQL8

啟動服務命令 net start mysql8 關閉服務命令 net stop mysql8 本地連接MySQL數據庫mysql -u [用戶名] -p[密碼] 這里&#xff0c;我遇到了個問題 —— 啟動、關閉服務時&#xff0c;顯示 “發生系統錯誤 5。拒絕訪問。 ” 解法1&#xff1a;在 Windows 上以管理員身份打開…

數據蒸餾:Dataset Distillation by Matching Training Trajectories 論文翻譯和理解

一、TL&#xff1b;DR 數據集蒸餾的任務是合成一個較小的數據集&#xff0c;使得在該合成數據集上訓練的模型能夠達到在完整數據集上訓練的模型相同的測試準確率&#xff0c;號稱優于coreset的選擇方法本文中&#xff0c;對于給定的網絡&#xff0c;我們在蒸餾數據上對其進行幾…

【spring cloud Netflix】Ribbon組件

1.基本概念 SpringCloud Ribbon是基于Netflix Ribbon 實現的一套客戶端負載均衡的工具。簡單的說&#xff0c;Ribbon 是 Netflix 發布的開源項目&#xff0c;主要功能是提供客戶端的軟件負載均衡算法&#xff0c;將 Netflix 的中間層服務連接在一 起。Ribbon 的客戶端組件提供…