C++標準規定了每個算術類型的最小存儲空間,但它并不阻止編譯器使用更大的存儲空間。事實上,對于 int 類型,幾乎所有的編譯器使用的存儲空間都比所要求的(16字節)大。
c語言和c++的內存管理
- c語言分四個區:堆,棧,全局區和常量區
- c++分五個區: 堆、棧、全局區、常量區和自由存儲區
c++的自由存取區類似于c語言的堆,存放的是malloc創建的內存,
基本類型
字符類型
字符類型有兩種:char 和 wchar_t。char 類型保證了有足夠的空間,能夠存儲機器基本字符集中任何字符相應的數值,因此,char 類型通常是單個機器字節(byte)。wchar_t 類型用于擴展字符集,比如漢字和日語,這些字符集中的一些字符不能用單個 char 表示。
整數型
short、int 和 long 類型都表示整型值,存儲空間的大小不同。一般, short類型為半個機器字長,int 類型為一個機器字長,而 long 類型為一個或兩個機器字長(在 32 位機器中 int 類型和 long 類型通常字長是相同的)。
浮點型
對于實際的程序來說,float 類型精度通常是不夠的——float 型只能保證 6 位有效數字,而 double 型至少可以保證 10 位有效數字,能滿足大多數計算的需要。
字面量
只有內置類型存在字面值,沒有類類型的字面值。因此,也沒有任何標準庫類型的字面值。
整型字面值
整型字面量可以有三種進制的表示:十進制、八進制和十六進制。以 0(零)開頭的字面值整數常量表示八進制,以 0x 或 0X 開頭的表示十六進制。
字面值整數常量的類型默認為 int 或 long 類型。其精度類型決定于字面值——其值適合 int 就是 int 類型,比 int 大的值就是 long 類型。通過增加后綴,能夠強制將字面值整數常量轉換,在數值后面加 L 或者 l(字母“l”大寫或小寫)指定常量為 long 類型。在數值后面加 U 或 u 定義 unsigned 類型。同時加 L 和 U就能夠得到 unsigned long 類型的字面值常量 。
用十進制或者科學計數法來表示浮點字面值常量。使用科學計數法時,指數用 E 或者 e 表示。默認的浮點字面值常量為 double 類型。在數值的后面加上 F 或 f 表示單精度。同樣加上 L 或者 l 表示擴展精度. 1e-3f 表示的是0.001.
字符型字面量
在字符字面值前加 L 就能夠得到 wchar_t類型的寬字符字面值。L'a'
字符串字面值
字符串字面值常量用雙引號括起來的零個或者多個字符表示。為了兼容 C 語言,C++ 中所有的字符串字面值都由編譯器自動在末尾添加一個空字符。"A" 表示包含字母 A 和空字符兩個字符的字符串。 也存在寬字符串字面值,一樣在前面加“L”,如 L"a wide string literal"寬字符串字面值是一串常量寬字符,同樣以一個寬空字符結束。
兩個相鄰的僅由空格、制表符或換行符分開的字符串字面值(或寬字符串字面值),可連接成一個新字符串字面值。這使得多行書寫長字符串字面值變得簡單:
string a = "123"
"456";
變量
變量名規則
變量名必須以字母或下劃線開頭,并且區分大小寫字母。char _;
初始化多個變量
當一個定義中定義了兩個以上變量的時候,每個變量都可能有自己的初始化式。 對象的名字立即變成可見,所以可以用同一個定義中前面已定義變量的值初始化后面的變量。
double salary = 9999.99, wage(salary + 0.01);
內置類型的變量只有在全局定義時才會被自動初始化為0, 而類的對象定義時如果沒有指定構造函數,不管是全局定義還是局部定義都會調用默認構造函數。
引用類型
引用(非const型)必須用與該引用同類型的對象初始化。
定義多個引用
在一行中定義多個引用時,每個名字簽名前都必須帶&,這一點與指針相似,因為它們都是復合類型
int i=1024, j=2048;
int &a=i, &b=j;
const引用
const引用是指向const對象的引用,不能用非const引用指向const對象,const引用當然也可以指向非const對象的引用。
非const引用只能綁定到與該引用同類型的對象。const引用則可以綁定到不同但相關類型的對象(多態或支持隱式類型轉換)或綁定到字面值常量上(這就是有限的兩個引用不同類型的例子)。
const int a = 1;
int b = 2;
int &c=a; //會報錯
const int &d=b ; //正確
const int &e = a; //正確
const int &f = 1; // 正確
int &g = 1; // 錯誤
auto &h=a; //正確 auto會保留底層const
auto &i=b; // 正確
auto &j=1; //錯誤,字面值需要指明const
const auto &k=1; //正確
對比,最后兩個表達式,我們知道編譯器可以從右值的對象中推斷出底層const,卻無法從字面量中推出,所以字面量必須顯式指出const auto;
當指向不同類型的對象時,會臨時創建一個對象進行類型轉換。
指針類型
指針與引用的區別
- 指針是一個對象,所以可以有賦值、取地址等操作,所以可以有指向指針的引用。
- 不強制必須初始化
除了兩種例外情況外,其它所有指針的類型都要和它所指向的對象嚴格匹配
例外1. const對象的指針指向同類型的非const對象(比引用嚴格,引用可以不同類型)
例外2. 多態的場合
空指針
c++11建議 使用字面值常量nullptr來將一個指針初始化為空指針
int *a=nullptr;
等價于 int *a=0;
以前的程序用的NULL其實是一個預處理變量,這個變量定義在頭文件cstdlib中,
c++建議初始化所有的指針,而常量指針在定義的時候必須初始化。
class與 struct
用class和struct關鍵字定義類的唯一差別在于默認訪問級別:默認情況下,struct的成員為public,而class的成員為private——《c++ primer》
類的定義
類的定義可以放在頭文件里面。
頭文件一般不包含定義,只包含extern 變量的聲明和函數的聲明。有三個例外:類的定義、值在編譯時就知道的const對象和inline函數——《c++ primer》
當我們在頭文件中定義了const變量后,每個包含這個頭文件的源文件都有了自己的const變量,當該const變量是用常量表達式初始化時,編譯器在編譯時會用常量表達式替換這些const變量,所以不會為每個源文件創建const對象的存儲空間。而當是用函數返回值或其它內容對const變量進行初始化時,編譯期間并不知道其值,所以就必須為其分配存儲空間,同時該const變量也不能定義在頭文件中。
類型別名
typedef和using都能定義類型別名
typedef double wages;
using wages=double;
如果某個類型別名指代的是符合類型或常量,那么把它用到聲明語句中就會產生意想不到的后果。
char tmp='a';
typedef char * pstring;
const pstring cstr=&tmp;
*cstr='b';
cstr=nullptr;
pstring const cstr2=&tmp;
*cstr2='b';
cstr2=nullptr;
其實cstr1和cstr2是同樣類型的對象。
auto
C++ 是靜態類型(statically typed)語言,在編譯時執行類型檢查。結果是程序中使用某個名字之前,必須先告知編譯器該名字的類型——《c++ primer》
auto的對象必須初始化,auto能在一條語句中,聲明多個變量。一條聲明語句只能由一個基本數據類型。auto可以推斷出指針,卻推不出引用,必須用auto &來定義一個引用。
auto i = 0, *p = &i;
auto的對象的類型有時候會和初始值的類型不完全一致
auto與引用
當用來為auto對象初始化的值是引用類型的時候,auto對象的類型是真正參與初始化的對象的值。
設置一個類型為auto的引用時,初始值終點頂層常量屬性仍然保留
const int a = 0;
int b = 0;
auto &b = a; // b是const int 類型的引用
auto c = a; // c是int類型
auto *d = &a, &e = b; // 編譯出出錯,因為&a是const int的地址,而b是int
auto與const
auto一般會忽略掉頂層const,同時底層const會被保留,比如當初始值是一個指向常量的指針時。
const int ci = 0, &cr = ci;
auto a = &ci; // 這時候a是const int * 類型的
auto b = cr; // b是int類型的
auto &c = ci; // c是const int & 類型的,因為是底層const
如果希望推斷出的auto類型是一個頂層const,則需要明確指出。
const auto f = ci;
decltype
c++11 引入了第二種類型說明符 decltype,它的作用是返回表達式返回值的類型,但是不會實際計算表達式的值。
decltype 遇到解引用操作將返回引用類型,引用類型的變量定義的時候必須初始化
int a;
int *p=&a;
decltype(*p) c=a; //注意這里必須初始化
decltype與變量,decltype((var))返回的是引用類型,decltype(var)返回的是正常類型。