C++入門全集(4):類與對象【下】

一、再談構造函數

1.1 構造函數體內賦值

我們知道,在創建對象時,編譯器會自動調用構造函數給對象中的各個成員變量一個合適的初始值

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};

雖然調用構造函數后,各個成員變量已經有了一個初始值,但是對于這種在函數體內賦值的語句不能稱為對成員變量的初始化,只能將其稱為賦初值。

因為初始化只能有一次,而構造函數體內可以寫多個賦值的語句,例如:

1.2 初始化列表

像這樣,被const修飾的成員變量,必須在聲明時就進行初始化

雖然C++11允許我們給成員變量一個缺省值,但是C++11以前是怎么做的呢?

這里引入一個新的概念:初始化列表

初始化列表定義在構造函數的函數名和函數體之間,以一個冒號開始,接著是一個用逗號分隔的數據成員列表,每個成員變量后面跟著一個放在括號中的初始值或表達式,例如:

Date(int year, int month, int day): _year(year), _month(month), _day(day)
{}

像這樣,才能稱之為真正的初始化

但是,如果一個成員變量既給了缺省值,又在初始化列表中顯式定義了,那它最后的值如何呢?

通過監視窗口我們可以觀察到:

如果一個成員變量既有缺省值又在初始化列表中定義了,那么就按照初始化列表中的值進行初始化

如果一個成員變量有缺省值,但是沒在初始化列表中定義,那么就用它的缺省值初始化

如果一個成員變量既沒有缺省值又沒在初始化列表中定義,那么就給一個隨機值

初始化列表有以下幾個特點:

(1)每個成員變量在初始化列表中只能出現一次,因為只能初始化一次

(2)類中的以下幾個成員變量,必須放在初始化列表中進行初始化

  • 引用類型的成員變量
  • const成員變量
  • 沒有默認構造函數的自定義類型成員變量

原因如下:?

對于引用類型的成員變量,我們必須在聲明變量時就給出它的引用對象

對于const成員變量前面已經提到過了,也是必須在聲明時就初始化

對于沒有默認構造函數的自定義類型成員變量,我們在初始化時需要傳參

(3)盡量多使用初始化列表去初始化,因為不管你是否使用,對于自定義類型成員變量都一定會先使用初始化列表去初始化

例如:

可以看到,Date類里有一個Time類的成員函數,雖然我們沒有在初始化列表中初始化它,它也會使用初始化列表去調用自己的默認構造函數

如果該自定義類型成員變量的構造函數不是無參的或者全缺省的,我們就需要手動將該變量添加至初始化列表中并給出參數。

總之,我們平時寫構造函數的時候盡量用初始化列表來初始化成員變量即可

(4)成員變量在類中的聲明順序就是它在初始化列表中的初始化順序,與其在初始化列表中的先后順序無關

例如:

class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};int main() {A aa(1);aa.Print();
}

最后打印的結果是什么呢?

可能很多人認為是 1 1,實際上是:

因為_a2比_a1先聲明,所以在初始化列表中也是_a2先初始化

最后,拷貝構造函數因為也是構造函數,所以它也有初始化列表?

1.3 explicit關鍵字

我們知道,內置類型變量在發生類型轉換的時候會生成一個臨時的常性變量,例如:

int a = 1;
double b = a;

但是,類型轉換不止能發生在內置類型中,內置類型也可以轉換成自定義類型,這里就和構造函數扯上關系了。

一個類的構造函數,不僅起到初始化成員變量的作用,對于單個參數或第一個參數無缺省值的半缺省構造函數來說,它還具有類型轉換的作用

或許沒看懂,那就舉一個例子

像這樣,對象aa1在創建時正常調用構造函數,aa2又是怎么回事?為什么一個自定義類型能被內置類型初始化?

前面說到,內置類型在發生類型轉換的時候會生成一個臨時的常性變量,這里也是一樣

首先編譯器使用1作為參數調用構造函數,創建一個臨時變量,再用這個臨時變量調用拷貝構造函數對aa2賦值

所以aa1只調用了一次構造函數,而aa2這一行代碼調用了一次構造函數和一次拷貝構造函數

這種方式既影響代碼可讀性,又增加了消耗,有什么辦法可以禁止構造函數類型轉換呢?

這里引入explicit關鍵字,在構造函數的前面加上它,即可禁止類型轉換了

這是單參數的構造函數,對于第一個參數無缺省值的半缺省構造函數也是同理

只要是只傳遞一個參數的構造函數,用這種方式都會發生類型轉換

另外,對于需要傳遞多個參數的構造函數,在C++11后也開始支持類型轉換了,例如:

如果不想類型轉換,用explicit修飾構造函數即可


二、static成員

2.1 概念

static修飾的類成員稱為類的靜態成員,static修飾的成員變量稱為靜態成員變量,static修飾的成員函數稱為靜態成員函數

有一道面試題:實現一個類,計算程序中創建過多少個類對象

可以看到,使用靜態成員變量和靜態成員函數可以很輕松的解決這個問題

2.2 特性

根據上面的圖,我們可以得出以下幾點?

(1)靜態成員不屬于某個對象,而是屬于所有對象、屬于整個類,存放在靜態區

所以我們上面可以直接使用類名和作用域限定符來訪問靜態成員函數GetCount,當然也可以創建一個對象來訪問靜態成員函數,但是有點多此一舉了

2)靜態成員變量必須在類外進行定義和初始化,不需要添加static,在類中聲明時才需要加

(3)靜態成員函數沒有隱式的this指針形參,所以不能訪問任何非靜態成員

(4)靜態成員也是類的成員,受public、protected和private訪問限定符的限制

像上面,因為_count是私有的,我們只能用函數來獲取它,如果它是公有的,我們也可以直接訪問


三、友元

當我們在類外定義了一個函數,想要訪問類中的私有成員變量怎么辦呢?這里就涉及到友元

友元提供了一種突破封裝的方式,有時提供了便利。但是友元會增加耦合度,破壞了封裝,所以友元不宜多用

友元又分為:友元函數友元類

3.1 友元函數

我們知道,cout和流插入運算符可以實現將內置類型打印的效果,那么假設我想將流插入運算符重載,讓自定義類型也可以使用呢?

我們試試在類中實現流插入運算符的重載函數

可以看到,實現的重載函數沒有起效

這是因為,成員函數的第一個變量是this指針,在重載函數中對應第一個變量的是第一個操作數

所以如果像這樣就可以正常運行了

但是這樣也太怪了吧,和平時用cout一點也不一樣,有沒有別的辦法呢?

我們只好在類外去實現流插入運算符的重載函數了,但是類外的函數又沒辦法訪問類內的私有成員

像這種必須定義在類外,但是又需要訪問類內的私有成員的函數,就需要友元來解決了

友元函數可以直接訪問類內的私有成員,需要在類的內部進行聲明,聲明時需要加friend關鍵字

需要說明以下幾點:

  • 雖然友元函數可以訪問類的私有和保護成員,但不是類的成員函數
  • 友元函數不能用const修飾
  • 友元函數可以在類的任何地方聲明,不受類訪問限定符限制
  • 一個函數可以同時是多個類的友元函數
  • 友元函數的調用和普通函數一樣

3.2 友元類

和友元函數類似,我們也可以在類中聲明一個友元類

友元類的所有成員函數都是另一個類的友元函數,都可以訪問另一個類中的非公有成員

需要注意以下幾點:

  • 友元關系是單向的,不具有交換性

比如上面,Date類是Time類的友元,所以可以直接在Date類中訪問Time類的私有成員變量;

但是不代表Time類是Date類的友元,不能在Time類中訪問Date類的私有成員變量

  • 友元關系不能傳遞

例如A是B的友元,B是C的友元,不代表A就是C的友元了

  • 友元關系不能繼承

這里在講到繼承后再給大家詳細介紹


四、內部類

4.1 概念

如果一個類定義在另一個類的內部,這個定義在內部的類就稱為內部類。

內部類是一個獨立的類,它不屬于外部類,我們更不能通過外部類的對象去訪問內部類的成員

外部類對內部類沒有任何優越的訪問權限。

內部類與外部類的關聯在于:

(1)內部類受外部類的類域限制

例如我們想創建一個內部類類型的變量,需要用作用域限定符

(2)內部類天生就是外部類的友元,但是外部類不是內部類的友元

4.2 特性

(1)內部類定義在外部類的public、protected和private中都是可以的

(2)內部類可以直接訪問外部類中的靜態成員,而不需要借助外部類的對象或類名

(3)外部類的大小不包括內部類

例如

可以看到,外部類A的大小并沒有包括內部類B,所以可以知道內部類的空間也是獨立的


五、匿名對象

有時候我們可能只需要調用一次某個類的成員函數,為此如果特意去創建一個對象的話就太麻煩了

這里就可以用到匿名對象。我們平時創建一個對象可能是這樣的:

如果要創建一個匿名對象的話,是這樣的:

顧名思義,匿名對象在創建的時候是不用取名字的。

匿名對象的特點在于,它的生命周期只在這一行,一旦程序走到了下一行,就會自動調用析構函數銷毀。

假設此時我們要調用一次A類中的Print函數,就可以用匿名對象去調用,而不用特意創建一個對象

對于各種一次性的對象創建,我們都可以使用匿名對象。

完.

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

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

相關文章

windows zip壓縮報錯includes characters that cannot be used in a compressed folder

Windows 用 zip 壓縮文件夾時報錯&#xff1a; <文件> cannot be compressed because includes characters that cannot be used in a compressed folder, such as <非法字符>. You should rename this file or directory.同 [1]。考慮用 python 批量檢測非 ascii…

SOCKS55代理 VS Http代理,如何選擇?

在使用IPFoxy全球代理時&#xff0c;選擇 SOCKS55代理還是HTTP代理&#xff1f;IPFoxy代理可以SOCKS55、Http協議自主切換&#xff0c;但要怎么選擇&#xff1f;為解決這個問題&#xff0c;得充分了解兩種代理的工作原理和配置情況。 在這篇文章中&#xff0c;我們會簡要介紹 …

我常用的大模型和Prompt有哪些?

常用的大模型及其對比 以前提到過&#xff0c;我們公司鼓勵大家多使用GPT這樣的大模型&#xff0c;一方面能夠提高工作效率&#xff0c;一方面使用的越多&#xff0c;越了解&#xff0c;越有可能發現應該怎么將其跟我們公司的產品結合起來。 但是出于安全考慮&#xff0c;如果…

Synchronized 詳解(一)

在C程序代碼中我們可以利用操作系統提供的互斥鎖來實現同步塊的互斥訪問及線程的阻塞及喚醒等工作。在Java中除了提供Lock API外還在語法層面上提供了synchronized關鍵字來實現互斥同步原語,本文將對synchronized關鍵字詳細分析。 帶著問題去理解Synchronized 提示 請帶著這…

10、BossCms代碼審計

1、任意文件上傳 限制 復現 POST /system/extend/ueditor/php/controller.php?actionuploadfile&encodeutf-8 HTTP/1.1 Host: bosscms.com Content-Length: 761 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome…

為什么要學習三維GIS開發?從技術層面告訴你答案

大家都知道GIS開發屬于GIS行業中就業薪資較高的崗位&#xff0c;并且測繪、遙感以及城規等相關專業的畢業生紛紛轉行做webgis開發。 那么&#xff0c;今天小編從技術層面探討一下&#xff0c;為什么建議大家不要僅僅停留在webgis&#xff0c;而要繼續往前學習三維GIS開發&…

TSINGSEE青犀AI智能分析網關V4智慧油田安全生產監管方案

一、方案背景 隨著科技的不斷發展&#xff0c;視頻監控技術在油田行業中得到了廣泛應用。為了提高油田生產的安全性和效率&#xff0c;建設一套智能視頻監控平臺保障安全生產顯得尤為重要。本方案采用先進的視頻分析技術、物聯網技術、云計算技術、大數據和人工智能技術&#…

Linux設備模型(十) - bus/device/device_driver/class

四&#xff0c;驅動的注冊 1&#xff0c;struct device_driver結構體 /** * struct device_driver - The basic device driver structure * name: Name of the device driver. * bus: The bus which the device of this driver belongs to. * owner: The module own…

JavaWeb Tomcat啟動、部署、配置、集成IDEA

web服務器軟件 服務器是安裝了服務器軟件的計算機&#xff0c;在web服務器軟件中&#xff0c;可以部署web項目&#xff0c;讓用戶通過瀏覽器來訪問這些項目。 Web服務器是一個應用程序&#xff08;軟件&#xff09;&#xff0c;對HTTP協議的操作進行封裝&#xff0c;使得程序…

MATLAB讀取txt文本數據及可視化指南

MATLAB讀取txt文本數據的說明指南 目錄 MATLAB讀取txt文本數據的說明指南摘要1. 數據準備2. 讀取數據3. 繪制圖形4. 小結 摘要 在MATLAB中&#xff0c;讀取txt文本格式文件數據是一項基本的操作&#xff0c;特別是在數據分析和可視化方面。本文將介紹如何使用MATLAB讀取txt文本…

C++ 基礎知識

一. 預備知識 1. C的編程方式 過程性語言 (結構化、自頂向下)、面向對象語言、泛型編程 (創建獨立于類型的代碼) 2. 創建源代碼文件的技巧 擴展名&#xff1a;.cpp 二. 第一個程序 - HelloWorld main() 入口點 返回 int 標準庫 iostream std: 標準庫的縮寫 Statement…

HarmonyOS-使用call事件拉起指定UIAbility到后臺

使用call事件拉起指定UIAbility到后臺 許多應用希望借助卡片的能力&#xff0c;實現和應用在前臺時相同的功能。例如音樂卡片&#xff0c;卡片上提供播放、暫停等按鈕&#xff0c;點擊不同按鈕將觸發音樂應用的不同功能&#xff0c;進而提高用戶的體驗。在卡片中使用postCardA…

科技的成就(五十七)

535、Machine Learning "1959 年 7 月&#xff0c;塞繆爾首創 Machine Learning 一詞。塞繆爾在“Some Studies in Machine Learning Using theGame of Checkers”一文中給 Machine Learning 下了個非正式定義&#xff1a;沒有明確編程指令的情況下&#xff0c;能讓計算機…

【js中的作用域】

理解 js中的作用我們可以分為三個部分 全局作用域函數作用域塊級作用域 全局作用域 不在任何函數內部或者大括號中聲明的變量,都是再全局作用域下,全局聲明的變量可以在程序中的任何位置訪問 函數作用域 函數作用域也叫局部作用域,如果一個變量聲名在一個函數內部,那么它…

LSTM進行字符級文本生成(pytorch實現)

文章目錄 基于pytorch的LSTM進行字符集文本生成前言一、數據集二、代碼實現 1.到入庫和LSTM進行模型構建2.數據預處理函數3.訓練函數4.預測函數5.文本生成函數6.主函數完整代碼總結 前言 本文介紹了機器學習中深度學習的內容使用pytorch構建LSTM模型進行字符級文本生成任務 一…

王者榮耀整蠱搭建直播新玩法/obs貼紙配置教程

最近很火的王者榮耀整蠱直播&#xff0c;相信很多玩王者的玩家也想開一個直播&#xff0c;但是看到這種直播娛樂效果很有意思也想搭建一個&#xff0c;這里夢哥給大家出了一期搭建的教程&#xff01; 進階版視頻教程&#xff1a; 這期的教程是進階版新玩法升級&#xff0c;具體…

Vue3:使用 Composition API 不需要 Pinia

在 Vue.js 開發的動態環境中&#xff0c;在單個組件中處理復雜的業務邏輯可能會導致笨重的文件和維護噩夢。雖然 Pinia 提供集中式狀態管理&#xff0c;但僅依賴它來處理復雜的業務邏輯可能會導致代碼混亂。本文探討了使用 Composition API 的替代方法&#xff0c;說明開發人員…

數據庫表 索引

目錄 一、索引的分類 1、按存儲形式: 1&#xff09;B-TREE索引&#xff1a; 2&#xff09;位圖索引&#xff1a; 3&#xff09;反向鍵索引&#xff1a; 4&#xff09;基于函數的索引&#xff1a; 2、按唯一性&#xff1a; 1&#xff09;唯一索引&#xff1a; 3、按列的個數…

代碼隨想錄算法訓練營第八天

344. 反轉字符串 方法&#xff1a; 方法一&#xff1a; 直接用reverse函數 注意&#xff1a; 代碼&#xff1a; class Solution { public:void reverseString(vector<char>& s) {return reverse(s.begin(), s.end());} };運行結果&#xff1a; 方法&#xff1…

解釋前端路由的概念,以及單頁應用(SPA)和多頁應用(MPA)的區別

前端路由是現代Web應用中的一種設計模式&#xff0c;它允許用戶在單個網頁應用程序&#xff08;SPA&#xff09;內部通過改變URL而無需重新加載整個頁面來切換不同的視圖或內容。在傳統的多頁應用&#xff08;MPA&#xff09;中&#xff0c;每訪問一個新頁面&#xff0c;瀏覽器…