變量和基本類型

靜態類型語言

C++ 是靜態類型(statically typed)語言,在編譯時執行類型檢查。結果是程序中使用某個名字之前,必須先告知編譯器該名字的類型。

什麼是變量

變量提供了程序可以操作的有名字的存儲區。C++ 中的每一個變量都有特定的類型,該類型決定了變量的內存大小和佈局、能夠存儲於該內存中的值的取值範圍以及可應用在該變量上的操作集。

初始化

變量定義指定了變量的類型和標識符,也可以爲對象提供初始值。定義時指定了初始值的對象被稱爲是已初始化的。C++ 支持兩種初始化變量的形式:複製初始化和直接初始化。複製初始化語法用等號(=),直接初始化則是把初始化式放在括號中:

int ival(1024); // direct-initialization
int ival = 1024; // copy-initialization

在 C++ 中理解“初始化不是賦值”是必要的。初始化指創建變量並給它賦初始值,而賦值則是擦除對象的當前值並用新值代替。

聲明和定義

變量的定義用於爲變量分配存儲空間,還可以爲變量指定初始值。在一個程序中,變量有且僅有一個定義。
聲明用於向程序表明變量的類型和名字。定義也是聲明:當定義變量時我們聲明瞭它的類型和名字。可以通過使用extern 關鍵字聲明變量名而不定義它。不定義變量的聲明包括對象名、對象類型和對象類型前的關鍵字extern:
extern int i; // declares but does not define i
int i; // declares and defines i
extern 聲明不是定義,也不分配存儲空間。事實上,它只是說明變量定義在程序的其他地方。程序中變量可以聲明多次,但只能定義一次。
只有當聲明也是定義時,聲明纔可以有初始化式,因爲只有定義才分配存儲空間。初始化式必須要有存儲空間來進行初始化。如果聲明有初始化式,那麼它可被當作是定義,即使聲明標記爲 extern:
extern double pi = 3.1416; // definition
雖然使用了 extern ,但是這條語句還是定義了 pi,分配並初始化了存儲空間。只有當 extern 聲明位於函數外部時,纔可以含有初始化式。
變量從聲明開始纔可見。

const 對象默認爲文件的局部變量

在全局作用域(第 2.3.6 節)裏定義非 const 變量時,它在整個程序中都可以訪問。我們可以把一個非 const 變更定義在一個文件中,假設已經做了合適的聲明,就可在另外的文件中使用這個變量:

// file_1.cc
int counter; // definition
// file_2.cc
extern int counter; // uses counter from file_1
++counter; // increments counter defined in file_1

與其他變量不同,除非特別說明,在全局作用域聲明的 const 變量是定義該對象的文件的局部變量。此變量只存在於那個文件中,不能被其他文件訪問。
通過指定 const 變更爲 extern,就可以在整個程序中訪問 const 對象:

// file_1.cc
// defines and initializes a const that is accessible to other files
extern const int bufSize = fcn();
// file_2.cc
extern const int bufSize; // uses bufSize from file_1
// uses bufSize defined in file_1
for (int index = 0; index != bufSize; ++index)
// ...

本程序中,file_1.cc 通過函數 fcn 的返回值來定義和初始化 bufSize。而 bufSize 定義爲 extern,也就意味着 bufSize 可以在其他的文件中使用。file_2.cc 中 extern 的聲明同樣是 extern;這種情況下,extern 標誌着bufSize 是一個聲明,所以沒有初始化式。
我們將會在第 2.9.1 節看到爲何 const 對象局部於文件創建。非 const 變量默認爲 extern。要使 const 變量能夠在其他的文件中訪問,必須地指定它爲 extern。

引用

引用就是對象的另一個名字。
引用是一種複合類型,通過在變量名前添加“&”符號來定義。複合類型是指用其他類型定義的類型。在引用的情況下,每一種引用類型都“關聯到”某一其他類型。

const 引用

const 引用是指向 const 對象的引用。
“非 const 引用”表示指向非 const 類型的引用。

const int ival = 1024;
const int &refVal = ival; // ok: both reference and object are const

const 引用可以初始化爲不同類型的對象或者初始化爲右值(第 2.3.1
節),如字面值常量:

int i = 42;
// legal for const references only
const int &r = 42;
const int &r2 = r + i;

同樣的初始化對於非 const 引用卻是不合法的,而且會導致編譯時錯誤。非 const 引用只能綁定到與該引用同類型的對象。

float、 double 和 long double

類型 float、 double 和 long double 分別表示單精度浮點數、雙精度浮點數和擴展精度浮點數。一般 float 類型用一個字(32 位)來表示,double 類型用兩個字(64 位)來表示,long double 類型用三個或四個字(96 或 128 位)來表示。類型的取值範圍決定了浮點數所含的有效數字位數。
對於實際的程序來說,float 類型精度通常是不夠的——float 型只能保證 6 位有效數字,而 double 型至少可以保證 10 位有效數字,能滿足大多數計算的需要。
決定使用哪種浮點型就容易多了:使用 double 類型基本上不會有錯。在 float 類型中隱式的精度損失是不能忽視的,而 double 類型精度代價相對於 float 類型精度代價可以忽略。事實上,有些機器上,double類型比 float 類型的計算要快得多。long double 類型提供的精度通常沒有必要,而且還需要承擔額外的運行代價。

字符串字面值的連接

兩個相鄰的僅由空格、製表符或換行符分開的字符串字面值(或寬字符串字
面值),可連接成一個新字符串字面值。這使得多行書寫長字符串字面值變得簡
單:

// concatenated long string literal
std::cout << "a multi-line "
             "string literal "
             "using concatenation"
          << std::endl;

執行這條語句將會輸出:
a multi-line string literal using concatenation
如果連接字符串字面值和寬字符串字面值,將會出現什麼結果呢?例如:

// Concatenating plain and wide character strings is undefined
std::cout << "multi-line " L"literal " << std::endl;

其結果是未定義的,也就是說,連接不同類型的行爲標準沒有定義。這個程序可能會執行,也可能會崩潰或者產生沒有用的值,而且在不同的編譯器下程序的動作可能不同。

多行字面值

處理長字符串有一個更基本的(但不常使用)方法,這個方法依賴於很少使用的程序格式化特性:在一行的末尾加一反斜線符號可將此行和下一行當作同一行處理。

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