難搞的“常宏靜”

寫在前面

他們沒有聯繫只有區別:不同層面上的東西。

  • #define: 預處理層面上的替換,不存在於語意層面
  • const: 變量的訪問控制:只讀(read-only)
  • static: 變量的作用域控制

——來自B乎某網友

談談我的個人理解

#define 宏定義

  • 編譯預處理期完成,完成文本替代,生成.i文件

  • 相當於AKA

#define Kris.吳 吳亦凡

∵吳亦凡 AKA Kris.吳

∴在代碼中直接用“Kris.吳”就可以代替“吳亦凡”了

  • 在預處理時候做的事,純粹的字符串替換,不會爲它分配空間

  • 存在一定缺陷:不安全,沒有類型檢查(既是優點,也是缺點吧…)

#define pos 3

那我怎麼知道pos是int,是float,還是double????

  • 一切都要括號
    • 整個表達式要括號
    • 參數出現的地方也要括號
#define square(x) ((x)*(x))

const 常量

關於本質

  • 最直觀的理解就是不能被修改,但存在很多細節
  • 它實際上就是變量,是需要分配空間
  • 編譯時就需要把確定下來

關於指針

Person p1("Fred",200);

// 指針所指對象不可以被修改
const Person* p = &p1;

// 指針所指對象不可以被修改
Person const* p = &p1;

// 指針不可以被修改
Person* const p = &p1;
  • 總結
    • const在*後面:指針不可以被修改
    • const在*前面:指針所指對象不可以被修改

關於字符串

char *s = "hello";
s[0] = 'B';

編譯會報Warning
segment fault : string constant to char*【段錯誤】

運行後會拋異常

爲什麼呢????????

因爲char *s = "hello";,相當於是放在代碼段不能被修改的內容

那怎麼改呢?

  • char前面加上const:這樣會報error: read-only(至少知道不能改,安全)
  • char s[] = "hello":實質就是把代碼段中的字符串,拷貝到堆棧段中,使之可操作

關於類的對象

// 所有成員變量的值都不能被修改
const Person p("Fred",200);

關於函數

  • 我們在前面知道,調用函數,是會開闢一個堆棧空間,把一些內容拷貝到堆棧段中的。如果想要使用某個對象,但又想節省空間,我們可以傳地址進來。
  • 如果擔心對象被修改,就可以const*來避免修改

  • 來看另外一個問題(f()中有const變量)
    • a.h:函數f()原型
    • a.cpp:函數f()的body
    • main.cpp:include"a.h",調用f()

這個時候編譯器會去找函數原型,可是這時候他不知道能不能改,他不知道body裏有啥,程序就沒法正常運行,咋辦???

這時候我們只需要void f() const就可以了,編譯器就知道了這個函數保證不會去動成員變量

但是爲什麼呢???

  • 我們來看一個class A裏的兩個函數
void f() {}
void f() const {}
  • 提問:他們構成重載嗎???——答案是:構成

爲啥??不是說傳入參數不一樣纔可以重載嗎????

是的,確實不一樣。我們將代碼細節還原:

void f(A* this) {}
// 函數const了,表示this是const,這個函數一定不動成員變量
void f(const A* this) const {}

其他

如果這時候有一個:

class A{
	const int i;
};

那麼它必須被初始化,我們可以在構造函數中,用初始化列表將他初始化。

static 靜態

static本地變量 = 全局變量

全局變量

  • 文件內可見,文件外不可見
  • 變量在全局數據區分配內存(局部變量在棧內,通過new和malloc動態分配的變量在堆裏)
  • 未經初始化的全局變量會被程序自動初始化爲0

局部變量

  • 單次初始化(函數內部),持久存儲(全局,編譯時分配空間)

  • 編譯器怎麼知道有沒有被初始化過?

    • 個人理解:或許類的內部有一個隱藏的成員變量來記錄
  • 靜態對象的生命週期

    • 構造:初始化時,main()前
    • 析構:程序結束時
  • 如果有多個.cpp的話,全局變量初始化順序是隨機的,如果這些變量之間有依賴的話,會報錯

    • 解決:去依賴,不用就完了;實在要用,有依賴關係的寫在一起
    • Java的解決:直接取消全局變量

成員變量

  • 對象間共享
  • 不能在初始化列表初始化
  • 如果寫在public內,可以在外部這麼用:
cout << A::i << endl;

成員函數

  • 對象間共享,只能訪問靜態成員變量/函數

  • 如果類A的public裏有個say()函數,可以這麼用(與Java類似)

A a;
a.say();
A::say();
  • 不可以用this(因爲如果直接A::say()的話,沒有對象)

誰能用

  • 靜態類、函數
  • main()

C語言:對外不公開的函數

  • 函數前加static:只能在所在編譯單元中被使用的函數
  • 全局變量前加static:只能在所在的編譯單元中被使用的全局變量

(編譯單元:一般一個.c文件就是一個編譯單元)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章