C++ 初始化列表(Initialization List)

来源:https://www.cnblogs.com/ruanchunyi/p/18196886
-Advertisement-
Play Games

請註意以下繼承體系中各class的constructors寫法: 1 class CPoint 2 { 3 public: 4 CPoint(float x=0.0) 5 :_x(x){} 6 7 float x() {return _x;} 8 void x(float xval){_x=xval ...


  請註意以下繼承體系中各class的constructors寫法:

 1 class CPoint
 2 {
 3 public:
 4     CPoint(float x=0.0)
 5     :_x(x){}
 6     
 7     float x() {return _x;}
 8     void x(float xval){_x=xval;}
 9 protected:
10     float _x;
11 };
12 
13 class CPoint2d:public CPoint{
14 
15 public:
16     CPoint2d(float x=0.0,float y=0.0)
17     :CPoint(x),_y(y){}
18 
19    float y(){return _y;}
20    void y(float yval){_y=yval;}
21 protected:
22     float _y;
23 };
24 
25 class CPoint3d:public CPoint2d{
26 public:
27     CPoint3d(float x=0.0,float y=0.0,float z=0.0)
28      :CPoint2d(x,y),_z(z){}
29      
30     float z(){return _z;}
31     void z(float zval){_z=zval;}
32 
33 protected:
34     float _z;
35 
36 
37 };

  在constructor聲明之後有一個:符號,後面緊跟著一個(以上)的函數調用動作,這一行就是所謂的initialization list。它的作用是在進入constructor主體動作之前,,先喚起其中所列的函數。例如上面的:

  第5行表示:在執行CPoint::CPoint(x)之前,先執行_x(x); (註:語言內建類型如int、float、long等等也是一種class,因為變數_x的類型是float,所以_x(x)的意思是啟動“float class”的constrnctor,也就把_x的初值設為x;

  第17行表示:執行CPoint2d::CPoint2d(x,y)之前,先執行CPoint(x)和_y(y).

  第28行表示:執行CPoint3d::CPoint3d(x,y,z)之前,先執行CPoint2d(x,y)和_z(z).

  因此當我產生一個CPoint3d object如下:

CPoint3d aPoint3d(1.1, 2.2, 3.3);

  會有以下六個動作依序被調用:

_x(1.1); // 相當於 _x = 1.1;
CPoint::CPoint(1.1); // 本例沒做什麼事
_y(2.2); // 相當於 _y = 2.2;
CPoint2d::CPoint2d(1.1, 2.2); // 本例沒做什麼事
_z(3.3); // 相當於_z = 3.3;
CPoint3d::CPoint3d(1.1, 2.2, 3.3); // 本例沒做什麼事

  你可能會問,既然繼承體系中的建構方式是由內而外,由上而下,那麼這裡產生個CPoint3d object,必然會調用CPoint2d和CPoint的constrnctor,而所有初始化動作都可以在其中完成,initialization list的出現會不會是顯得多此一舉?做個測試就知道了,把上一段27行的代碼改為這樣試試:

CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }

  其中沒有指定initialzation list。結果竟然無法通過編譯:

error C2668: 'CPoint2d::CPoint2d' : ambiguous call to overloaded
function

  也就是說,當編譯器根據繼承體系往上一層調用base class constructor時,發現CPoint2d有兩個constructors,而它不知道應該調用哪一個。這就是initialization list最明顯的存在的價值。如果本例的CPoint2d只有一個constructor,像這樣:

1 class CPoint2d : public CPoint {
2 public:
3   CPoint2d( ) { _y = 0.0; } // default constructor
4 protected:
5   float _y;
6 };

  或者這樣

1 class CPoint2d : public CPoint {
2 public:
3     CPoint2d( float x = 0.0, float y = 0.0 )
4     : CPoint( x ), _y( y ) { }
5 protected:
6     float _y;
7 };

  而 CPoint3d constructor 中沒有列出 initialization list,像這樣:

1 class CPoint3d : public CPoint2d {
2 public:
3     CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }
4 protected:
5     float _z;
6 };

  那麼並不會出現前面的編譯錯誤。

  以上的討論是針對base class的建構,同理對於member class 也是一樣。如果member calss有一個以上的constructors,那麼內含embedded object的那個class就必須在其constructor中指定initialization list,否則一樣會出現編譯錯誤。

  initialization list到底會在編譯器底層發生什麼影響呢?編譯器會以“適當的次序”將initialization list中指定的member調用動作安插到constructor之內,並置於任何user code之前,下麵這張圖可以表現出編譯器的插碼結果:

 

   有一些微妙的地方必須註意,編譯器安插在constructor中的members聲明動作是以members在class中的聲明次序為根據,而不是以initializtion list中的排序為根據。如果兩者在外觀上錯亂,很容易引起程式設計時的一些困擾或失誤。例如:

class X {
public:
    X(int val) : m_data2(val), m_data1(m_data2) { }
protected:
    int m_data1;
    int m_data2;
};

  我們很容易誤以為在X constructor中是以val 設定m_data2,再將m_data2設定給m_data1.但根據兩個data members的聲明順序,實際發生的動作卻是:

1 X::X(int val)
2 {
3     m_data1(m_data2); // 此時 m_data2 還沒有初值,糟糕
4     m_data2(val);
5 }

  於是,當我們產生一個X object:

X x(3);

  其實data members的內容可能成為這樣:

x.m_data1 = -2124198216 // 這不是我們希望的
x.m_data2 = 3

一個比較好的做法是,把class X重新設計如下:

1 class X {
2 public:
3     X(int val) : m_data2(val) { m_data1 = m_data2; }
4 protected:
5     int m_data1;
6     int m_data2;
7 };

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 在家沒事的時候刷抖音玩,抖音首頁的視頻怎麼刷也刷不完,經常不知不覺的一刷就到半夜了 不禁感嘆道 "垃圾抖音,費我時間,毀我青春" 這是我的 模仿抖音 系列文章的第二篇,本文將一步步實現抖音首頁 視頻無限滑動 的效果,乾貨滿滿 第一篇:200行代碼實現類似Swiper.js的輪播組件 第 ...
  • 一、錯誤類型 任何一個框架,對於錯誤的處理都是一種必備的能力 在Vue 中,則是定義了一套對應的錯誤處理規則給到使用者,且在源代碼級別,對部分必要的過程做了一定的錯誤處理。 主要的錯誤來源包括: 後端介面錯誤 代碼中本身邏輯錯誤 二、如何處理 後端介面錯誤 通過axios的interceptor實現 ...
  • 目錄VUE-局部使用快速入門常用指令v-forv-bindv-if & v-showv-onv-modelvue生命周期AxiosVue案例 VUE-局部使用 Vue 是一款用於構建用戶界面的漸進式的JavaScript框架。 (官方:https://cn.vuejs.org/) 快速入門 準備 準 ...
  • 前言 在上一篇 vue3早已具備拋棄虛擬DOM的能力了文章中講了對於動態節點,vue做的優化是將這些動態節點收集起來,然後當響應式變數修改後進行靶向更新。那麼vue對靜態節點有沒有做什麼優化呢?答案是:當然有,對於靜態節點會進行“靜態提升”。這篇文章我們來看看vue是如何進行靜態提升的。 什麼是靜態 ...
  • 一般我們在開發的時候,習慣上使用常規的關係型資料庫來設計資料庫表,對於一些業務表的欄位比較固定的場景,是一種非常不錯的選擇,而且查詢的時候,由於是基於固定的表欄位進行查詢,性能基本上是最優的。不過有一些場景下,業務信息的經常變化,使用常規的關係型資料庫來創建表欄位、刪除欄位的模式,肯定不是合適的處理... ...
  • 項目場景: 之前正式一直都是使用的手動註冊,而且測試環境還沒有註冊上去,但是最近開發的需要每天在測試上跑跑看,再上生產,所以這次要解決掉。 問題描述 我是測試環境和正式環境都在一臺機子上,兩個環境項目跑不同的docker容器,我要做的是這兩個容器裡面的項目都註冊到我的xxl服務上去。 而且之前情況是 ...
  • 1、先將字體複製到目錄:\vendor\mpdf\mpdf\ttfonts2、再修改文件\vendor\mpdf\mpdf\src\Config\FontVariables.php,對照已經添加的simsun,simkai,simhei,fangzhenweibei,fangzhenheiti等字體 ...
  • nginx 反向代理是什麼? nginx 反向代理是一種網路伺服器架構模式,它通過將客戶端的請求轉發到後端伺服器,來提供負載均衡、高可用性、安全性等功能。 在這種架構中,nginx 作為反向代理伺服器,接收來自客戶端的請求,並將請求轉發到後端伺服器上。 在反向代理架構中,客戶端不直接訪問後端伺服器, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...