C語(yǔ)言確實(shí)很優(yōu)雅,整個(gè)語(yǔ)言的設(shè)計(jì)簡(jiǎn)潔一致。而在C++中,有一個(gè)讓人詬病的問(wèn)題就是變量初始化的不一致性。
C語(yǔ)言中的初始化,都是用花括號(hào)進(jìn)行,簡(jiǎn)單美觀:
int array[] = {1,2,3,4,5};
struct Point point = {2, 3};
struct Point arrPoint[] =
{
{2,3},
{4,5},
{6,7}
};
C++自然也兼容了C語(yǔ)言的初始化機(jī)制。然而,C++的Class乃至STL都不支持。它們要用不同的方式來(lái)初始化, 甚至根本不能夠直接初始化, 只能使用運(yùn)行時(shí)的賦值。
比如Class:
class Param
{
public:
int Age;
int Value;
private:
int Level;
};
Param param = {2,3}; // ERROR
Param param = {2,3,4}; //ERROR
無(wú)法初始化。而如果不初始化的話,所有的成員而處于無(wú)政府狀態(tài),這顯然很不讓人放心。于是,C++提供了專門用于Class的初始化方式--構(gòu)造函數(shù):
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;
有了構(gòu)造函數(shù),可以在構(gòu)造函數(shù)的初始化列表中對(duì)成員進(jìn)行初始化。可是很明顯,這里頭還是有一個(gè)陷阱,默認(rèn)構(gòu)造初始化和非默認(rèn)構(gòu)造初始化的調(diào)用方式是不一致的。默認(rèn)構(gòu)造函數(shù)不能用括號(hào)來(lái)調(diào)用,否則編譯器將會(huì)發(fā)瘋:
Param param();
它會(huì)把上面的語(yǔ)句看成是函數(shù)聲明,而后面調(diào)用的時(shí)候就會(huì)出錯(cuò),而錯(cuò)誤信息可能會(huì)讓你抓狂一下。但是這樣也就算了,偏偏 new 可以接受有括號(hào)和沒(méi)括號(hào)兩種寫法:
Param* p1 = new Param;
Param* p2 = new Param();
再來(lái)說(shuō)說(shuō)初始化列表。初始化列表,事實(shí)上,也只能支持簡(jiǎn)單的標(biāo)量類型,諸如int,bool,指針之類的;復(fù)雜點(diǎn)的,如數(shù)組、結(jié)構(gòu),不好意思,不支持--只能在構(gòu)造函數(shù)體中進(jìn)行賦值。還有一個(gè)很迷糊初學(xué)者的問(wèn)題是,成員初始化的順序僅依賴于成員定義的順序,而不是初始化列表中的順序。
再比如STL容器,這下好象更慘,連構(gòu)造函數(shù)都幫不上忙了,除了初始化一個(gè)空的容器,或是復(fù)制一下別的容器,我們只能做用默認(rèn)構(gòu)造函數(shù)進(jìn)行初始化。我們拿數(shù)組和vecotr做個(gè)比較:
// 數(shù)組
int arr[]={1,2,3,4};
// vector
vector<int> iarr;
// 必須在某個(gè)函數(shù)中賦初值
void init()
{
for(int i = 1; i <= 4; ++i)
iarr.push_back(i);
}
再?gòu)?fù)雜一點(diǎn)的數(shù)據(jù)結(jié)構(gòu),那單單賦值程序就要寫上老長(zhǎng),而且還不好看。還要記得調(diào)用。這對(duì)于僅僅是簡(jiǎn)單的設(shè)置一些初值的用途來(lái)說(shuō),太過(guò)于煩瑣。
橫向比較,這次好象C++還不會(huì)太落伍,只有C和動(dòng)態(tài)語(yǔ)言提供了初始化特性,其它支持OO高級(jí)語(yǔ)言好象都是學(xué)C++的。如Java, C#(注C#3.0開(kāi)始提供初始化功能)...
C++能不能做到簡(jiǎn)潔一致的實(shí)始化呢?
Boost的assign庫(kù)做了許多有益的工作。使用assign庫(kù),至少現(xiàn)在可以初始化了:
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();
如果是賦值,也可以簡(jiǎn)略很多:
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]
不過(guò),也僅能如此了。assign經(jīng)過(guò)許多努力,也僅能支持容器的初始化,而且還不夠漂亮。
C++0x已確定提供與C一致的初始化功能。
Initialer lists Initializer Lists for Standard Containers Initializer lists WP wording 等草案就是為了這個(gè)目的服務(wù)的。
如果使用C++0x,那么程序的初始化將變得清晰和一致:
complex<double> z = {1,2};
//或
complex<double> z {1,2};
// 初始化中,有等號(hào)和無(wú)等號(hào)都是允許的,下同。
z += {2,3};
int a = {1};
new vector<string>{"once", "upon", "a", "time"};
f( {"Nicholas", "Annemarie"} ); // 參數(shù)是兩個(gè)元素的列表
return { "Norah" }; // 返回只有一個(gè)元素的列表
int* e {}; // 初始化為0或NULL指針
map<string,int> anim =
{
{"bear",4},
{"cassovary",2},
{"tiger",7}
};
這好象是C++欠了十多年的債吧。