前面介紹了什麼是變量,以及變量的命名與定義,現在我們來了解一下變量的初始化。
我們都知道,在定義一個變量時,需要明確它的類型和變量名,其實,有時候我們也要爲變量設定一個初始值。這樣在變量定義時就已被賦值的變量,就是初始化的變量,這個賦值操作稱爲初始化。
C++語言支持兩種初始化的格式:copy-initialization(複製初始化)和direct-initialization(直接初始化)。複製初始化在語句中使用等號;直接初始化則將初始值寫在小括號內。如下,爲ival賦值1024:
int ival(1024); //direct-initialization
int ival=1024; //copy-initialization
在C++程序的編寫中,直接初始化比複製初始化的使用要更加靈活。
很多人將變量的初始化看做賦值的一種,但是在C++中這是兩個不同的操作符(原書觀點)。在其他的語言中,這種區別是很少見的,並且是可以不考慮的。儘管這樣,在C++中也要很複雜的程序編寫中才會體現出初始化和賦值的區別。
—————————————————————————————————————————————————
多重初始化程序的應用
當我們初始化一個內置數據類型的變量時,我們要做的只有:提供一個值,別且把這個值複製到被定義的變量中。對於內置數據類型的變量,直接初始化和複製初始化只有很小的區別。但是,對於類類型的變量,我們只能用直接初始化的方式來進行變量的初始化。爲了理解這點,我們需要先了解下類對於初始化操作的控制。
每一個類都是由一個或者多個元函數(成員函數)組成,這些元函數恰恰影響了類類型變量的初始化。這些決定類類型變量初始化的元函數通常稱爲構造函數(constructor)。像其他的函數一樣,構造函數也擁有很多的參數(argument)。每個類都會定義一些構造函數,這些構造函數必須包含不同數目或者類型的參數。下面我們來簡單看看string類以便於我們理解。
string類是定義成庫函數並且可以作用於變化長度的字符串的類。爲了使用string類,我們必須include這個類的標題,像IO類型,string類是定義在std的命名空間的。
sting類定義了一些構造函數,這給了我們很多途徑去初始化string。其中一種就如複製一個字符串常量:
#include <string>
// alternative ways to initialize string from a character string literal
std::string titleA="C++ Primer, 4th Ed.";
std::string titleB("C++ Primer, 4th Ed.");
在這個例子中,兩種初始化操作都是合法的,它們都創建了一個初始值是特定字符串常量的sting變量。不僅僅是常量,我們也可以通過數量和字符來初始化sting,這樣做可以創建一個包含重複一定數量的字符的string:
std::string all_nines(10, '9'); //all_nines="9999999999"
在這個例子中,我們只能通過直接初始化來初始化all_nines,用複製初始化來進行多重初始化程序的操作。
—————————————————————————————————————————————————
初始化多個變量
如同定義一個一樣,在定義多個變量時,每個變量一般都有其自己的初始化程序。在定義變量的時候,變量名的後面加上初始化的變量值,使得這個變量更加直觀。在命名語句中,可能同時存在初始化的和非初始化的變量,而且複製初始化和直接初始化可以混合使用。如下:
#include <string>
double salary=9999.99,
wage(salary+0.01);
int interval,
month=8, day=7, year=1995;
std::string title ("C++ Primer, 4th Ed."),
publisher="A-W";
任何表達式都可以用作變量的初始化,包括函數的返回值。如下:
double price=109.99, discount=0.16;
double sale_price=apply_discount(price, discount);
在這個例子中,apply_discount是一個包含兩個double型參數並且返回值是double型的函數,我們可以把計算所得apply_discount的返回值來初始化sale_price這個變量。
—————————————————————————————————————————————————
變量的初始化潛規則
在定義一個變量時,如果我們沒有進行初始化操作,系統有時候會幫我們完成初始化。至於初始化的值,主要取決於變量的類型以及被定義的位置。
不管怎樣,在函數外定義的變量都被初始化爲0。而如果是在函數體內定義的內置型變量,通常是未初始化的。把任何未初始化變量當做左值來使用的賦值行爲都是未定義的行爲,隨之引起的錯誤很難被發現。所以這種未定義的行爲實不可取的。
—————————————————————————————————————————————————
類類型變量的初始化
每個類都會定義它的對象的初始化方式,它通過定義不同的構造函數來控制變量的初始化。例如,在string類中至少有兩個構造函數,一個使我們可以初始化爲字符串常量,另一個使我們可以初始化爲字符或者是數量。
類同樣定義了初始化程序對於被定義的變量類型不可用的結果,這是通過定義默認構造函數(default constructor)來實現的。之所以稱爲默認構造函數,是因爲當變量沒有被初始化的時候,這個函數是默認運行的,而且不管這個變量是在哪裏被定義的。
很多的類都會定義默認構造函數,如果一個類定義了默認構造函數的話,我們有時就不需要一對一的對變量進行初始化操作。例如,string類型定義了一個默認構造函數,使得“string”稱爲一個空的字符串常量:
std::string empty; //empty is the empty string; empty=""
對於那些沒有定義默認構造函數的類,我們必須針對每個變量進行初始化操作。