追蹤

宗宗大學

喜歡關注科學、哲學、社會、政治、教育,未來想當一位抱著理想的科學家,期許社會能夠進步。

[筆記]static / const成員資料與函式|C++


non-const static成員資料無法在類別內初始化,也無法使用初始化列,那到底該如何初始化?static成員是什麼概念?可以將自己宣告為自己的成員資料嗎?如果可以,該如何實現?如果不行,會發生什麼問題?

還是很困惑嗎?文章裡有答案喔~😎

一、靜態 (static)與常數 (const)

(一)成員資料 (data member)

C++11:允許non-static成員資料在類別中直接初始化

  1. const static int m1 = 7; // ok
  2. const             int m2 = 7; // ok
  3.             static int m3 = 7; // error: not const
  4.                         int m4 = 7; // ok

那要如何初始化第三個例子 (non-const static 成員資料)呢?non-const static 成員資料無法在類別中初始化,只能在class外初始化,而且不能放在.h檔中,必須放在.cpp。

方法1:在.cpp宣告

 宣告的時候,class外的變數不能加上static且前面要加上領域,如果不給值,預設就是0。

一般而言,鏈結器會合併 C++ 樣版產生的函式或變數,所以我們可以利用這個特性宣告靜態資料成員,然後以 vector<void*>::count存取該變數:

  

template<>

class vector<void*>{

public:

    ...

    ...

private:

    std::vector<void*> vec;

    static int count; // 在.h檔宣告

};

 

int vector<void*>::count = 0; // 要在.cpp檔宣告

 

方法2:使用內嵌變數 C++17

inline variable (C++17)

動機:因為編譯 C++ 函式庫通常必需處理很瑣碎的細節,所以一些函式庫作者傾向將整個實作都放在標頭檔,使用者只要引用標頭檔就能直接使用函式庫。這類函式庫我們通常稱為 Header-Only Library(標頭檔函式庫)。然而編寫 Header-Only Library 並不是一件簡單的事。

 

Inline Variable(內嵌變數)是以 inline 關鍵字修飾的變數(包含全域變數或靜態資料成員);以 constexpr 關鍵字修飾的靜態資料成員也是 Inline Variable。

 

template<>

class vector<void*>{

public:

    ...

    ...

private:

    std::vector<void*> vec;

    inline static int count = 0; // Method 1

    inline static int count  {0}; // Method 2

    static int count; // Method 3.1

};

 

inline int vector<void*>::count = 0; // Method 3.2 在.h檔中宣告

(二)成員函式

static for class,static 成員函式和成員資料,不需要先宣告物件/實例,就可以直接匿名呼叫使用。non-static for instance,必須要先宣告物件/實例,才能使用non-static 成員函式和成員資料。

const 物件只能存取const成員函式,但non-const物件可以存取cons和non-const成員函式,const成員函式不能改變類別的成員資料,但可以存取類別的成員資料

(三)JAVA static物件

C++ const 相似於JAVA final,Java: final

  1. 類別:當宣告在類別上時,該類別就無法被繼承!
  2. 函數:當一個函數被宣告為final時,則繼承他的子類別無法覆寫
  3. 變數:當一個變數被宣告為final時,意思是他是一個常數,是無法被修改的。

在JAVA可以在class中宣告自己的static物件 (objects)/實例 (instances),也就是class中自帶自己的static物件。因此可以在class中宣告:

  1. public static final className variableName = new className(argument list); //合法
  2. public static            className variableName = new className(argument list); // 合法
  3. public              final className variableName = new className(argument list); // 無限遞迴
  4. public                         className variableName = new className(argument list); // 無限遞迴

重點在於static這個保留字,static可避免落入無限遞迴的陷阱中。因為宣告static的變數,在實例化的過程中,static變數早就已經初始化過了,故不會去再去初始化這個變數,因此就不會落入無限遞迴。

static變數的存取,不用真的實例化一個物件,即可直接匿名存取static變數,因為static變數早就已經初始化過了,故可以直接存取其值,例如:className.staticVar。而非static變數的存取,一定要先實例化後,才能存取此變數,因為尚未實例化也代表non-static variable尚未初始化,故沒有值也當然無法存取。

舉個例子,有個類別叫水果,水果類別有顏色和大小這兩個資料。如果顏色是static變數,且在定義時就給定此顏色為紅色。則我們在實例化時,就只需要提供大小去實例化紅色水果。我們可以實例化出紅色大芭樂、紅色中蘋果、紅色小葡萄,因此即使這三個實例尚未被實例化,我們也可以知道此水果類別的顏色是紅色。

而non-static大小就必須要實例化後,才能得知,因爲non-static大小不是所有物件共享的資料;而static 顏色是所有物件都共享的資料,也就是紅色是所有紅色水果共享的特徵。因此如果將水果類別的static 顏色改成黃色,所有的實例顏色全部皆為黃色,即黃色大芭樂、黃色中蘋果、黃色小葡萄。

因此static資料成員是被所有物件所共享的特徵,且此特徵在實例化前,就已經被初始化給值,故在實例化時,就不會理static資料成員,故不會落入無限遞迴。

即使JAVA能夠在類別內宣告自己的內別物件,但C++仍無法:

C++編譯器無法區分這是一個成員函數還是一個成員變數!

static const Type ch("char", static_cast<int>(Tag::_BASIC), 1); // 在Type類別內宣告一個Type物件1

Expected parameter declarator

但在C++中依舊會出錯!因為編譯器會認定這是一個不完整的結構!

static const Type ch = Type("char", static_cast<int>(Tag::_BASIC), 1); // 在Type類別內宣告一個Type物件2

Invalid use of incomplete type 'Type'

因為編譯到這裡時還沒有發現定義,不知道該類或者結構的內部成員,沒有辦法具體的構造一個對象,所以會報錯。

二、相關文章

  1. 物件導向程式設計|模擬真實世界的方式|江明朝
  2. AOOP Homework source code
  3. [筆記]109-2高等物件導向程式設計 期中考
  4. [筆記]介面與實作、運算子多載、左值右值、參數傳遞、回傳多值|C++
  5. [筆記]陣列與指標|C++
  6. [筆記]類別、特殊函式、內嵌函式、函式物件|C++
  7. [筆記]繼承模式與存取權限|C++
  8. [筆記]多型與繼承的關係|C++
  9. [筆記]static / const成員資料與函式|C++
  10. [筆記]夥伴函式與類別、不夠朋友問題|C++

本文章發表於:課程

加入85

宗宗大學

國立中山大學 生物科學系

追蹤 384 鼓勵作者

喜歡關注科學、哲學、社會、政治、教育,未來想當一位抱著理想的科學家,期許社會能夠進步。

鼓勵作者

目前持有 Blink Coin: Loading..

選擇禮物


愛心

(Coin 10)

幫高調

(Coin 20)

咖啡

(Coin 30)

掌聲鼓勵

(Coin 40)

崇拜眼神

(Coin 50)

驚呆了

(Coin 60)

神人4ni

(Coin 70)

花束

(Coin 100)

鑽石

(Coin 300)

紅寶石

(Coin 500)

藍寶石

(Coin 1000)

黃寶石

(Coin 3000)


送出鼓勵



發表匿名文章不會出現你的大頭圖與名稱,你可暢所欲言,但文章內容務必遵守「佈告欄使用規範」!


回應

送出回應


想回應這篇文章嗎?也想發表文章嗎?
馬上登入來發表文章、追蹤作者、收藏文章或回應文章吧!

註冊 登入