<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
C++有很多初始化物件的方法。其中之一叫做 聚合體初始化(aggregate initialization) ,這是聚合體專有的一種初始化方法。
從C語言引入的初始化方式是用花括號括起來的一組值來初始化類:
struct Data { std::string name; double value; }; Data x = {"test1", 6.778};
自從C++11起,你可以忽略等號:
Data x{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"test1", 6.778};
自從C++17起,聚合體可以擁有基礎類別。也就是說像下面這種從其他類派生出的子類也可以使用這種初始化方法:
struct MoreData : Data { bool done; } MoreData y{{"test1", 6.778}, false};
如你所見,聚合體初始化時可以用一個子聚合體初始化來初始化類中來自基礎類別的成員。
另外,你甚至可以省略子聚合體初始化的花括號:
MoreData y{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"test1", 6.778, false};
這樣寫將遵循巢狀聚合體初始化時的通用規則,你傳遞的實參被用來初始化哪一個成員取決於它們的順序。
如果沒有這個特性,那麼所有的派生類都不能使用聚合體初始化,這意味著你要像下面這樣定義建構函式:
struct Cpp14Data : Data { bool done; Cpp14Data (const std::string& s, double d, bool b) : Data{s, d}, done{b} { } }; Cpp14Data y{"test1", 6.778, false};
現在我們不再需要定義任何建構函式就可以做到這一點。
我們可以直接使用巢狀花括號的語法來實現初始化,
如果給出了內層初始化需要的所有值就可以省略內層的花括號:
MoreData x{{"test1", 6.778}, false}; // 自從C++17起OK MoreData y{"test1", 6.778, false}; // OK
注意因為現在派生類也可以是聚合體,所以其他的一些初始化方法也可以使用:
MoreData u; // OOPS:value/done未初始化 MoreData z{}; // OK: value/done初始化為0/false
如果覺得這樣很危險,可以使用成員初始值:
struct Data { std::string name; double value{0.0}; }; struct Cpp14Data : Data { bool done{false}; };
或者,繼續提供一個預設建構函式。
聚合體初始化的一個典型應用場景是對一個派生自C風格結構體並且新增了新成員的類進行初始化。例如:
struct Data { const char* name; double value; }; struct CppData : Data { bool critical; void print() const { std::cout << '[' << name << ',' << value << "]n"; } }; CppData y{{"test1", 6.778}, false}; y.print();
這裡,內層花括號裡的引數被傳遞給基礎類別Data
。
注意你可以跳過初始化某些值。在這種情況下,跳過的成員將會進行預設初始化
(基礎型別會被初始化為0
、false
或者nullptr
,類型別會預設構造)。
例如:
CppData x1{}; // 所有成員預設初始化為0值 CppData x2{{"msg"}} // 和{{"msg", 0.0}, false}等價 CppData x3{{}, true}; // 和{{nullptr, 0.0}, true}等價 CppData x4; // 成員的值未定義
注意使用空花括號和不使用花括號完全不同:
x1
的定義會把所有成員預設初始化為0值,
因此字元指標name
被初始化為nullptr
,
double
型別的value
初始化為0.0
,
bool
型別的flag
初始化為false
。x4
的定義沒有初始化任何成員。所有成員的值都是未定義的。
你也可以從非聚合體派生出聚合體。例如:
struct MyString : std::string { void print() const { if (empty()) { std::cout << "<undefined>n"; } else { std::cout << c_str() << 'n'; } } }; MyString x{{"hello"}}; MyString y{"world"};
注意這不是通常的具有多型性的public
繼承,因為std::string
沒有虛成員函數,
你需要避免混淆這兩種型別。
你甚至可以從多個基礎類別和聚合體中派生出聚合體:
template<typename T> struct D : std::string, std::complex<T> { std::string data; };
你可以像下面這樣使用和初始化:
D<float> s{{"hello"}, {4.5, 6.7}, "world"}; // 自從C++17起OK D<float> t{"hello", {4.5, 6.7}, "world"}; // 自從C++17起OK std::cout << s.data; // 輸出:"world" std::cout << static_cast<std::string>(s); // 輸出:"hello" std::cout << static_cast<std::complex<float>>(s); //輸出:(4.5,6.7)
內部巢狀的初值列表將按照繼承時基礎類別宣告的順序傳遞給基礎類別。
這個新的特性也可以幫助我們用很少的程式碼定義過載的lambda
。
總的來說,在C++17中滿足如下條件之一的物件被認為是 聚合體 :
class
、struct
、union
):explicit
的建構函式using
宣告繼承的建構函式private
和protected
的非靜態資料成員virtual
函數virtual, private, protected
的基礎類別然而,要想使用聚合體初始化來 初始化 聚合體,那麼還需要滿足如下額外的約束:
private
或者protected
的成員private
或者protected
的建構函式下一節就有一個因為不滿足這些額外約束導致編譯失敗的例子。
C++17引入了一個新的型別特徵is_aggregate<>
來測試一個型別是否是聚合體:
template<typename T> struct D : std::string, std::complex<T> { std::string data; }; D<float> s{{"hello"}, {4.5, 6.7}, "world"}; // 自從C++17起OK std::cout << std::is_aggregate<decltype(s)>::value; // 輸出1(true)
注意下面的例子不能再通過編譯:
struct Derived; struct Base { friend struct Derived; private: Base() { } }; struct Derived : Base { }; int main() { Derived d1{}; // 自從C++17起ERROR Derived d2; // 仍然OK(但可能不會初始化) }
在C++17之前,Derived
不是聚合體。因此
Derived d1{};
會呼叫Derived
隱式定義的預設建構函式,這個建構函式會呼叫基礎類別Base
的建構函式。
儘管基礎類別的預設建構函式是private
的,但在派生類別建構函式裡呼叫它也是有效的,
因為派生類被宣告為友元類。
自從C++17起,例子中的Derived
是一個聚合體,所以它沒有隱式的預設建構函式
(建構函式沒有使用using
宣告繼承)。因此,d1
的初始化將是一個聚合體初始化,
如下表示式:
std::is_aggregate<Derived>::value
將返回true
。
然而,因為基礎類別有一個private
的建構函式(見上一節)所以不能使用花括號來初始化。
這和派生類是否是基礎類別的友元無關。
到此這篇關於C++聚合體初始化aggregate initialization詳細介紹的文章就介紹到這了,更多相關C++聚合體初始化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45