C++的第一道門坎:類與對象(一)

1.面向過程與面向對象

1.1面向過程

我們之前學習的C語言就是一種面向過程的語言,面向過程的語言強調的是具體實現的過程,一般用函數來具體實現。我們用面向過程的思想,就可以把炒菜分為以下幾個步驟:

1.2面向對象

而對于面向對象的語言而言,它將問題分為了多個對象,問題的解決由對象之間的交互完成,而不再注重對象完成事情的具體過程,譬如上述炒菜的過程我們即可抽象為人、菜、鍋的交互。

C++即是一門面向對象的語言,我們更強調對象之間的交互,而并不在意對象該如何解決問題。?

1.3對比

面向過程的語言和面向對象的語言各有其優缺點:

面向過程的語言流程化分工明確,效率高,但可維護性差,拓展能力差。

面向對象的語言結構化更清晰,易維護,但開銷大,性能低。

2.類的引入

在C++中,我們在結構體的基礎上引入了類(class)的概念,并對struct在CPP的基礎上重新進行了解釋。

由于我們的面向對象不注重過程的實現,但是對象本身還是需要實現過程的,因此我們要給對象加上一定的過程,比如我們的人鍋交互可以炒菜,我們就要在類中聲明一個作用是炒菜的函數。

也就是說,CPP的類和結構體中可以定義成員函數!

2.1類的聲明方式

在C++中,有一個關鍵字為class,我們可以使用這個關鍵字來聲明一個類,類內可以聲明成員函數和成員變量,其語法結構為:

class 類名
{//類內的成員函數和成員變量
};

現在我們聲明一個名為duanku的類:

class duanku
{int a;//成員變量int Add(int a, int b);//成員函數
};

2.2類的成員的兩種定義方式

在定義類時,我們可以將類的定義與聲明在同一文件書寫,也可以在不同文件內書寫。

2.2.1單文件定義

定義一個類,自然需要實現類體內的函數,我們可以將函數在類內定義,如下所示:

class duanku
{int a;//成員變量int Add(int a, int b)//成員函數{return a + b;}
};

這里需要大家注意的是:成員函數若在類內定義,則可能會被編譯器當作內聯函數處理。

2.2.2多文件定義

一個類也可以分為兩個文件來實現,我們可以將成員函數的定義放在cpp文件內部。

但這兒需要大家注意的一點是:你定義的函數是誰的函數呢?是只在這個文件內部用的,還是實現了哪個地方的聲明呢?因此,我們需要加域作用限定符,讓編譯器知道我們實現的是哪個函數。

//.h文件
class duanku
{int a;//成員變量int Add(int a, int b);//成員函數
};
//.cpp文件
int duanku::Add(int a, int b)
{return a + b;
}

?PS:在日常使用時,我們可以將定義和聲明都放在類中。但是在實際的工程中,更傾向于將聲明和定義分離。

3.類的訪問限定符與封裝

3.1訪問限定符

在C++類中有三種訪問限定符:public、private、protect

它們的作用如下

  • public修飾的成員可以在類外直接訪問
  • private和protect修飾的成員在類外不可直接被訪問(后續文章會詳細解釋private和protect)
  • 一個類中可以有多個訪問限定符,一個限定訪問符的作用域該限定訪問符出現的位置到下一個限定訪問符出現的位置,如果后面沒有限定訪問符,則到類結束的位置為止。
  • class的默認訪問權限為private,struct的默認訪問權限為public(下篇文章中會給出class和struct的詳解)

3.2封裝

封裝:用類將對象的屬性(數據)與操作數據的方法結合在一塊,讓對象更加完善,通過訪問權限選擇性的將其接口提供給外部的用戶使用。

通俗的說,封裝其實是一種管理,是為了方便讓用戶更方便的使用類的一種方法。

比如說:對于一臺電腦而言,我們提供給用戶的是一系列的USB接口,我們可以通過它們和計算機進行一系列的交互,也可以自由更改每個USB接口的接什么,但是我們無法更改電腦的硬件元件。

這里,我們可以這樣理解:

每個USB接口都是一個函數,我們可以自由更改它們,它們的訪問限定為public。

而硬件元件則是類中的私有成員,不讓外界訪問,它們的訪問限定為private。

4.類對象

4.1類對象的實例化

在類中定義的成員變量實際上是一種聲明,而我們利用類名字定義的對象就是類對象的實例化

即,用類的類型創造對象的過程,稱為類的實例化

1.類是對對象進行描述的,是一個模型一樣的東西,限定了類中有哪些成員,定義出一個類并不會分配實際的內存空間來存儲它。

2.一個類可以實例化出多個對象,實例化出的對象才占用實際的內存空間,存儲的是類的成員變量。

我們不可以直接利用類來進行定義,如下圖所示

?正確的定義方法如下:

	Date a;a._year = 3;

4.2類對象的存儲

我們已經知道了類對象的創建方式,那么具體類中的成員變量與成員函數又是如何存儲的呢?

4.2.1 存儲方式1

每次創建對象時,都開辟一個空間存儲類中的成員變量與成員函數。

但是這樣存儲就會出現一個問題,成員函數都是用的一個函數,我們每次都創建一個豈不是會有很大的開銷嗎?一個就能行的事兒為什么要用很多個呢?

于是,我們的計算機中,大多數都不是這么存儲對象的。

4.2.2 存儲方式2

?我們首先將成員函數放在外面,之后我們每次創建對象時,都開辟一個空間存儲類成員變量與成員函數的地址,需要成員函數的時候直接按照地址去找。

4.2.3存儲方式3

每次創建對象時,都開辟一個空間存儲類成員變量。而成員函數提前單獨存儲在另外一個區域(公共代碼段)。

之后我們沒去用到成員函數時,都去那個區域里面拿出來用。

一般的編譯器采用的都是存儲模式2或存儲模式3,具體使用的是哪種存儲模式,我們可以通過計算類大小來進行判斷。?

4.3類對象的大小

4.3.1普通類對象的大小

類型對象的大小也遵循結構體的內存對齊規則:

1.類的第一個成員對齊到結構體變量起始位置偏移量為0的地址處

2.其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。

? ?對齊數=編譯器默認的一個對齊數與該成員變量大小的較小值

? ?--VS2022中的默認對齊數是8

? ?--Liunx中gcc沒有默認對齊數,對齊數就是成員自身的大小

3.類總大小為所有成員對齊數中的最大對齊數的整數倍

4.如果嵌套了結構體,嵌套的結構體成員對齊到自己的成員的最大對齊數處,結構體的整體大小就是所有成員的最大對齊數(含嵌套結構體成員)的整數倍。

當然,類大小的計算我們可以也借助sizeof計算。

#include<iostream>
using namespace std;
class Date
{
//可以被直接訪問
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}
//不能被直接訪問
private:int _year;int _month;int _day;
};
int main()
{Date d;cout << sizeof(d) << endl;return 0;
}

?

由此可見,我們這里算出來的12是三個int類型的總和,而我們的成員函數則被放到了公共代碼段中。 若是使用的存儲模式2的話,則應該是12+成員函數地址的大小(32位系統是4,64位系統是8)。

?4.3.2空類的計算

當類中只有成員函數,或者什么都沒有時,類的大小是多少呢?

class A
{
public:void func(){;}
};
class B
{
};
int main()
{A a;B b;cout << sizeof(a)<<endl << sizeof(b);return 0;
}

?

這里我們發現空類的大小為1,現在我們可以思考這么一個問題,為什么空類的大小是1而不是0呢??這是因為我們在進行空類的實例化時必須要有空間表示我們在這兒存儲了一個對象。這時編譯器就會默認給一個字節大小來標記這個對象

5.this指針

5.1this指針的由來

#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, d2;d1.Init(2022, 1, 11);d2.Init(2022, 1, 12);d1.Print();d2.Print();return 0;
}

在這里我先給大家拋出這么一個問題:為什么d1調用Init函數時,該函數知道是給d1對象調用Init,而不是給d2對象調用Init呢??

在C++中通過引入this指針解決該問題,即:C++編譯器給每個“非靜態的成員函數“增加了一個隱藏的指針參數。通過不同的對象地址來分辨不同的對象,只不過所有的操作對用戶是透明的的,即用戶不需要來傳遞,編譯器自動完成。實際代碼如下:

void Init(Date* this, int year, int month, int day)
{this->_year = year;this->_month = month;this->_day = day;
}
d1.Init(&d1,2022, 1, 11);//實際傳參

5.2this指針的特點

  1. this指針額類型為const,即我們無法給this指針賦值
  2. this指針的本質是“成員函數”的形參,當對象調用成員函數時,會將對象的地址當作實參傳遞給形參。
  3. this指針只能在成員函數中使用
  4. this指針是“成員函數”第一個隱藏起來的指針形參,一般由編譯器放在通過eax寄存器自動傳遞,不需要用戶傳遞

5.3兩個問題

5.3.1問題1

// 1.下面程序編譯運行結果是? A、編譯報錯 B、運行崩潰 C、正常運行
class duanku
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{duanku* p = nullptr;p->Print();(*p).Print();return 0;
}

這段代碼是可以正常運行的,雖然p是一個空指針,但是由于我們的成員函數放在公共代碼段中,因此我們還是可以找到這個函數的,不會因為對空指針解引用而找不到它。

5.3.2問題2

// 1.下面程序編譯運行結果是? A、編譯報錯 B、運行崩潰 C、正常運行
class duanku
{
public:void Print(){cout << _a << endl;}
private:int _a;
};
int main()
{duanku* p = nullptr;p->Print();(*p).Print();return 0;
}

這里就會讓程序崩潰,因為函數中訪問了_a?,nullptr->_a程序就崩潰了。

?6.成員變量的命名

大家在使用類時,可能會出現以下這么一個問題:

這時為了解決問題這類問題,我們在定義成員變量時會對其進行特定地修飾。比如說_變量名或者變量名_。不同公司,不同的程序員可能都有一套自己的命名規則,這里我們采用第一種。

由此我們可以將上述代碼改寫為這樣:

class Date
{void Init(int year, int month, int day){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};

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

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

相關文章

【簡單介紹下容器是什么?】

&#x1f3a5;博主&#xff1a;程序員不想YY啊 &#x1f4ab;CSDN優質創作者&#xff0c;CSDN實力新星&#xff0c;CSDN博客專家 &#x1f917;點贊&#x1f388;收藏?再看&#x1f4ab;養成習慣 ?希望本文對您有所裨益&#xff0c;如有不足之處&#xff0c;歡迎在評論區提出…

【Spring】Spring AOP底層原理:JDK動態代理和CGLIB動態代理

目錄 1、代理模式 1.1、靜態代理 1.2、動態代理 2、JDK 動態代理 2.1、jdk動態代理簡介 2.2、使用JDK動態代理機制步驟 3、CGLIB 動態代理 3.1、CGLIB 動態代理的特性 3.2、CGLIB的核心類 3.3、CGLIB 動態代理步驟 4、JDK 和 CGLIB 創建代理對象的區別 ?編輯 1、…

通關!游戲設計之道Day16

皆大歡喜計費點 游戲行業中有一項設計顯得越來越重要&#xff0c;那就是計費點設計 是開發者琢磨出來的一系列手段&#xff0c;讓玩家買了游戲之后&#xff0c;還能繼續付費 對于把玩家跟他們的錢拆散&#xff0c;游戲開發者們總是樂此不疲 來看幾個能讓開發者額外多賺些錢…

(四)手把手教你內網穿透,實現外網主機訪問內網服務器

背景&#xff1a;書接上回&#xff0c; 服務器的使用-CSDN博客 課題組成員都有自己的賬號&#xff0c;且能通過內網訪問服務器&#xff0c;進行遠程連接了。我們知道內網中的主機可以訪問公網的主機&#xff0c;反之不可以訪問。那么如果課題組成員在家不在內網區域內&#x…

源碼編譯安裝LAMP與部署

目錄 一、LAMP架構的簡述 1.LAMP搭建時各組件安裝順序 二、編譯安裝Apache httpd服務 1.關閉防火墻&#xff0c;將安裝Apache所需軟件包傳到/opt目錄下 2.安裝環境依賴包?編輯 3.配置軟件模塊 4.編譯及安裝 5.優化配置文件路徑&#xff0c;并把httpd服務的可執行程序文…

基于51單片機的智能燈光控制系統

一.硬件方案 智能燈光控制系統由單片機最小系統、人體感應模塊、關照強度模塊、燈光控制模塊、電源模塊和燈泡組成。本文以STC89C52單片機為核心&#xff0c;通過利用光照度和紅外人體感應相結合主動與被動的探測方法&#xff0c;現了室內無人或者關照充足時燈光自動光燈&…

Kubernetes 容器資源管理Resources和探針Probe

資源配額 Resources 在 Kubernetes 中&#xff0c;resources 配置用于設置容器的資源請求和限制&#xff0c;以確保集群中的資源&#xff08;如 CPU 和內存&#xff09;得到合理分配和使用。 在之前的pod中&#xff0c;不寫 resources 字段。就意味著 Pod 對運行的資源要求“…

Java面試八股之AQS對資源的共享方式

AQS對資源的共享方式 AQS設計了一套靈活的機制&#xff0c;不僅支持獨占&#xff08;Exclusive&#xff09;鎖模式&#xff0c;也支持共享&#xff08;Shared&#xff09;鎖模式&#xff0c;使得資源可以被一個或者多個線程以不同的方式訪問。這兩種模式通過控制一個內部的vol…

技術速遞|宣布 Java on Azure 開發工具支持 Azure Functions Flex Consumption

作者&#xff1a;Jialuo Gan 排版&#xff1a;Alan Wang Azure Functions Flex Consumption 剛剛在微軟 Build 2024大會期間發布&#xff08;詳情請參見本博客&#xff09;。我們很高興地與大家分享&#xff0c;Azure Functions 的 IntelliJ Azure Toolkit 和 Maven 插件現在也…

pyqt QTableView表格控件

pyqt QTableView表格控件 QTableView效果代碼 QTableView QTableView 是 PyQt中的一個控件&#xff0c;用于顯示表格數據。它通常與 QAbstractItemModel 或其子類&#xff08;如 QStandardItemModel&#xff09;一起使用&#xff0c;以提供和管理表格中的數據。 效果 代碼 i…

wordpress主題 ACG美化插件v3.4.2支持zibll主題7b2主題美化

獨具一格的二次元風格&#xff0c;打造全新的子比美化方向 大部分代碼均為CSS、JS做成插件只是為了方便懶人小白站長 后臺全功能一覽&#xff0c;大部分美化均為網上通用流傳&#xff0c;

2.冒泡排序

樣例輸入 5 8 3 6 4 9 樣例輸出 3 4 6 8 9 以下是解題答案&#xff1a; class demo1{public static void main(String[] args) {Scanner scnnew Scanner(System.in);int[] array new int[scn.nextInt()];if(array.length>0&&array.length<200){for(int…

python列表訪問的深入解析

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、正向索引與負索引的奧秘 二、切片&#xff1a;高效訪問多個元素 切片示例 三、切片的…

MIT6.828 Lab2-3 Sysinfo

目錄 一、實驗內容二、實驗過程2.1 已有的代碼2.2 需補充內容/kernel/kalloc.c修改&#xff08;剩余內存計算的函數&#xff09;/kernel/proc.c修改&#xff08;統計進程數量的函數&#xff09;/kernel/defs.h修改添加/kernel/sysinfo.c文件/kernel/syscall.h修改/kernel/sysca…

Java 文件操作和輸入輸出流

在 Java 編程中&#xff0c;文件操作和輸入輸出流是非常常見和重要的任務&#xff0c;它們允許你讀取和寫入文件、處理數據流等。 文件操作概述 文件操作是指對文件進行創建、讀取、寫入、刪除等操作的過程。在 Java 中&#xff0c;文件操作通常涉及到使用文件對象、輸入輸出…

OpenBayes 一周速覽|TripoSR 開源:1 秒即 2D 變 3D、經典 GTZAN 音樂數據集上線

公共資源速遞 This Weekly Snapshots &#xff01;5 個數據集&#xff1a; FER2013 面部表情識別數據集 GTZAN 音樂流派分類數據集 MVTec-AD 工業異常檢測數據集 UCAS-AOD 遙感目標檢測數據集 Oxford 102 Flowers 花卉圖片數據集 3 個教程&#xff1a; Latte 全球首個開…

利用ArcGIS Python批量拼接遙感影像(arcpy batch processing)

本篇文章將說明如何利用ArcGIS 10.1自帶的Python IDLE進行遙感影像的批量拼接與裁剪。 1.運行環境&#xff1a;ArcGIS10.1 (安裝傳送門)、Python IDLE 2.數據來源&#xff1a;地理空間數據云 GDEMV2 30M分辨率數字高程數據 3.解決問題&#xff1a;制作山西省的DEM影像 如下…

【WEB前端2024】開源智體世界:喬布斯3D紀念館-第30課-門的移動動畫

【WEB前端2024】開源智體世界&#xff1a;喬布斯3D紀念館-第30課-門的移動動畫 使用dtns.network德塔世界&#xff08;開源的智體世界引擎&#xff09;&#xff0c;策劃和設計《喬布斯超大型的開源3D紀念館》的系列教程。dtns.network是一款主要由JavaScript編寫的智體世界引擎…

服務器端口轉發,服務器端口轉發的作用、好處與壞處

服務器端口轉發&#xff0c;服務器端口轉發的作用、好處與壞處。 服務器端口轉發是一種關鍵的網絡技術&#xff0c;它在網絡安全和通信中發揮著不可替代的作用。其主要功能是將來自一個端口的網絡流量轉發到另一個端口&#xff0c;從而實現內外網之間的流量交互。這種技術通常…

雷軍-2022.8小米創業思考-8-和用戶交朋友,非粉絲經濟;性價比是最大的誠意;新媒體,直播離用戶更近;用真誠打動朋友,臉皮厚點!

第八章 和用戶交朋友 2005年&#xff0c;為了進一步推動金山的互聯網轉型&#xff0c;讓金山的同事更好地理解互聯網的精髓&#xff0c;我推動了一場向谷歌學習的運動&#xff0c;其中一個小要求就是要能背誦“谷歌十誡”。 十誡的第一條就令人印象深刻&#xff1a;以用戶為中…