C語言確實很優雅,整個語言的設計簡潔一致。而在C++中,有一個讓人詬病的問題就是變量初始化的不一致性。
C語言中的初始化,都是用花括號進行,簡單美觀:
int array[] = {1,2,3,4,5};
struct Point point = {2, 3};
struct Point arrPoint[] =
{
{2,3},
{4,5},
{6,7}
};
C++自然也兼容了C語言的初始化機制。然而,C++的Class乃至STL都不支持。它們要用不同的方式來初始化, 甚至根本不能夠直接初始化, 只能使用運行時的賦值。
比如Class:
class Param
{
public:
int Age;
int Value;
private:
int Level;
};
Param param = {2,3}; // ERROR
Param param = {2,3,4}; //ERROR
無法初始化。而如果不初始化的話,所有的成員而處于無政府狀態,這顯然很不讓人放心。于是,C++提供了專門用于Class的初始化方式--構造函數:
class Param
{
public:
Param(int x, int y)
: x_(x), y_(y)
{}
Param()
: x_(0), y_(0)
{}
private:
int x_, y_;
};
Param param(1,2);
//或
Param param;
有了構造函數,可以在構造函數的初始化列表中對成員進行初始化。可是很明顯,這里頭還是有一個陷阱,默認構造初始化和非默認構造初始化的調用方式是不一致的。默認構造函數不能用括號來調用,否則編譯器將會發瘋:
Param param();
它會把上面的語句看成是函數聲明,而后面調用的時候就會出錯,而錯誤信息可能會讓你抓狂一下。但是這樣也就算了,偏偏 new 可以接受有括號和沒括號兩種寫法:
Param* p1 = new Param;
Param* p2 = new Param();
再來說說初始化列表。初始化列表,事實上,也只能支持簡單的標量類型,諸如int,bool,指針之類的;復雜點的,如數組、結構,不好意思,不支持--只能在構造函數體中進行賦值。還有一個很迷糊初學者的問題是,成員初始化的順序僅依賴于成員定義的順序,而不是初始化列表中的順序。
再比如STL容器,這下好象更慘,連構造函數都幫不上忙了,除了初始化一個空的容器,或是復制一下別的容器,我們只能做用默認構造函數進行初始化。我們拿數組和vecotr做個比較:
// 數組
int arr[]={1,2,3,4};
// vector
vector<int> iarr;
// 必須在某個函數中賦初值
void init()
{
for(int i = 1; i <= 4; ++i)
iarr.push_back(i);
}
再復雜一點的數據結構,那單單賦值程序就要寫上老長,而且還不好看。還要記得調用。這對于僅僅是簡單的設置一些初值的用途來說,太過于煩瑣。
橫向比較,這次好象C++還不會太落伍,只有C和動態語言提供了初始化特性,其它支持OO高級語言好象都是學C++的。如Java, C#(注C#3.0開始提供初始化功能)...
C++能不能做到簡潔一致的實始化呢?
Boost的assign庫做了許多有益的工作。使用assign庫,至少現在可以初始化了:
vector<int> arr = list_of(1)(2)(3)(4);

typedef boost::tuple<int,std::string,int> tuple;
vector<tuple> v = tuple_list_of( 1, "foo", 2 )( 3, "bar", 4 );

map<int,int> next = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);

stack<string> names = list_of( "Mr. Foo" )( "Mr. Bar")( "Mrs. FooBar" ).to_adapter();
如果是賦值,也可以簡略很多:
vector<int> v;
v += 1,2,3,repeat(10,4),5,6,7,8,9;
// v = [1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,7,8,9]
不過,也僅能如此了。assign經過許多努力,也僅能支持容器的初始化,而且還不夠漂亮。
C++0x已確定提供與C一致的初始化功能。
Initialer lists Initializer Lists for Standard Containers Initializer lists WP wording 等草案就是為了這個目的服務的。
如果使用C++0x,那么程序的初始化將變得清晰和一致:
complex<double> z = {1,2};
//或
complex<double> z {1,2};
// 初始化中,有等號和無等號都是允許的,下同。
z += {2,3};
int a = {1};
new vector<string>{"once", "upon", "a", "time"};
f( {"Nicholas", "Annemarie"} ); // 參數是兩個元素的列表
return { "Norah" }; // 返回只有一個元素的列表
int* e {}; // 初始化為0或NULL指針
map<string,int> anim =
{
{"bear",4},
{"cassovary",2},
{"tiger",7}
};
這好象是C++欠了十多年的債吧。