寫在前面
他們沒有聯繫只有區別:不同層面上的東西。
- #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文件就是一個編譯單元)