首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

深度探索 C++ 對象模型(四):構造函數語義與編譯器合成機制

     編輯:VC 教學

閱讀《深度探索 C++ 對象模型》第一章雖然仍有疑惑,但收穫頗豐。根據經驗,第一章屬於概覽性介紹,具體細節留待後續章節闡述。若未通讀全書,單看第一章確實較難理解。第一章讓我從最初的「世界末日」感中走出,信心倍增,也摸索出一些門徑。繼續踏上深度探索 C++ 對象模型的旅程,記住「堅持不懈,直到成功」是通往成功的不二法門。

第二章:構造函數語義

第二章探討構造函數語意。筆者認為「Semantics」譯為「語義」較為恰當:語義學研究語言形式表達意義的科學。本章旨在以語言形式清晰描述構造函數的工作機制。

構造函數基礎回顧

構造函數是類的成員函數,與類同名,無返回值(連 void 也不能有)。主要負責對象數據的創建、初始化;析構函數負責清理。構造函數可重載,析構函數不可重載。重載區別僅在參數列表(個數或類型)。

本章核心:構造函數如何工作

本章不講構造函數是什麼,而是講它如何構造對象。這正是筆者一直好奇的:為何類實例化時能自動完成諸多工作,使主函數清晰、簡單、穩健、高效?書中重點討論編譯器合成預設構造函數的幾種情況。

情況一:含有預設構造函數的成員對象

若類無任何構造函數,但擁有成員對象,且該成員對象的類有預設構造函數,編譯器會在必要時為該類合成一個構造函數(內聯方式)。

// 範例類別
class Cat  { public: Cat(); ... };
class Dog  { public: Dog(); ... };
class Bird { public: Bird(); ... };
class Fish { public: Fish(); ... };

class Pet {
public:
    Cat  aCat;
    Dog  aDog;
    Bird aBird;
    Fish aFish;
private:
    int ival;
    ...
};

編譯器合成的構造函數大致如下:

inline Pet::Pet() {
    aCat.Cat::Cat();
    aDog.Dog::Dog();
    aBird.Bird::Bird();
    aFish.Fish::Fish();
    ival = 0;
}

若程式設計師自行定義 Pet::Pet() { ival = 0; },編譯器仍會將其擴展為上述形式。編譯器在生成對象前,先調用必要的構造函數初始化成員,以分配適當記憶體空間。

比喻:律師與官司

若你惹上官司(設計類),卻無錢聘請高級律師(未提供構造函數),法院會指派律師(預設構造函數)。這律師能力或許不如大律師(trivial),但在律師行督導下(編譯器合成),能盡力做到最好,成為 nontrivial default constructor。

其他非平凡預設構造函數情況

  • 繼承自帶有預設構造函數的基類:派生類預設構造函數視為 nontrivial,合成時按聲明順序調用基類預設構造函數。
  • 類聲明或繼承虛函數、或含虛擬基類:編譯器合成預設構造函數以正確初始化每個對象的 vptr(虛函數表指標)。

合成構造函數的初始化範圍

合成的預設構造函數僅初始化基類子對象與類的成員對象;其他非靜態數據成員不會被初始化,這些工作留給程式設計師完成。

侯大師曾說:「練從難處練,用從易處用。知其然而不知其所以然,不是嚴謹的學習態度。」深入理解編譯器合成機制,有助於寫出更健壯、高效的 C++ 程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved