初始化代碼寫到崩潰?這個(gè) C++ 魔法必須安排上!
大家好啊! ?? 我是 everystep,今天讓我們來(lái)聊聊 C++ 中的聚合初始化這個(gè)有趣的話題。不過(guò)在開始之前,讓我們先來(lái)聽(tīng)聽(tīng)這個(gè)魔法特性的小故事~
很久很久以前(其實(shí)也就是 C++98 的年代啦 ??),程序員們?cè)诔跏蓟兞繒r(shí)可是遇到了不少煩惱呢。那時(shí)候的初始化就像是一場(chǎng)混亂的舞會(huì) ??,大家都在用著不同的方式跳舞:有人喜歡用圓括號(hào)(),有人偏愛(ài)等號(hào)=,還有人鐘情于花括號(hào){}。這可讓代碼世界亂成一鍋粥啦! ??
直到有一天,C++11 的標(biāo)準(zhǔn)委員會(huì)決定要給這場(chǎng)舞會(huì)定下新規(guī)則。他們說(shuō):"讓我們創(chuàng)造一個(gè)統(tǒng)一的初始化方式吧!" 于是,聚合初始化這個(gè)可愛(ài)的小精靈就誕生啦! ??♀? 它不僅統(tǒng)一了初始化的語(yǔ)法,還帶來(lái)了很多意想不到的驚喜呢~
比如說(shuō),它可以防止類型收窄(narrowing),就像是給我們的數(shù)據(jù)穿上了一件防護(hù)服 ???。如果你試圖把一個(gè) double 偷偷塞進(jìn) int 里面,它就會(huì)大聲說(shuō)"不行!" 這可幫助我們避免了很多調(diào)皮的 bug 呢! ??
到了 C++17,這個(gè)小精靈又學(xué)會(huì)了新魔法,它可以在嵌套初始化時(shí)省略一些煩人的花括號(hào),讓代碼看起來(lái)更整潔啦! ? 而在 C++20 中,它更是學(xué)會(huì)了給每個(gè)值都貼上標(biāo)簽的本領(lǐng),這下再也不會(huì)認(rèn)錯(cuò)誰(shuí)是誰(shuí)啦! ???
現(xiàn)在的聚合初始化就像是一位溫柔又可靠的管家,幫我們把所有的初始化工作都打理得妥妥當(dāng)當(dāng)?shù)?。無(wú)論是簡(jiǎn)單的數(shù)組、結(jié)構(gòu)體,還是復(fù)雜的嵌套類型,它都能輕松應(yīng)對(duì)! ???
基本語(yǔ)法 - 讓我們開始這場(chǎng)魔法表演吧! ???
// 瞧瞧這個(gè)最基礎(chǔ)的寫法,就像魔術(shù)師揮舞魔法棒 "噔噔咚~" ?
// 所有的值都乖乖排好隊(duì),準(zhǔn)備入住它們的新家啦! ??
T object = { arg1, arg2, ... };
// C++11 來(lái)了個(gè)小改良,連等號(hào)都省掉啦!
// 就像快遞直接送到家,完全不用簽收 ????
T object { arg1, arg2, ... };
// 到了C++20,簡(jiǎn)直就像給每個(gè)小可愛(ài)都貼上了名牌!
// 再也不會(huì)認(rèn)錯(cuò)誰(shuí)是誰(shuí)啦 ??
// 就像幼兒園小朋友的書包和水杯,每個(gè)都有自己的標(biāo)簽 ???
T object = { .name = "小明", .age = 18 }; // 多可愛(ài)呀! ??
瞧瞧,這些初始化方式就像是在變魔術(shù)一樣神奇,對(duì)吧? ?? 每種方式都有它自己的小特色,就像是不同口味的糖果,你最喜歡哪一種呢? ?? 無(wú)論選擇哪種方式,它們都會(huì)幫我們把數(shù)據(jù)整整齊齊地收拾好,就像是給玩具找到了完美的收納盒! ???
來(lái)看個(gè)有趣的例子 - 打造我們的小小冒險(xiǎn)世界! ?? ??
想象一下,我們正在創(chuàng)造一個(gè)充滿魔法的游戲世界,需要召喚一些勇敢的小英雄來(lái)拯救世界~ 讓我們看看如何給這些可愛(ài)的勇者們安排他們的冒險(xiǎn)裝備吧! ??♂??
// 這就是我們勇者的基本配置單,就像是英雄的簡(jiǎn)歷表一樣! ??
struct GameCharacter {
std::string name; // 英雄的閃亮名字 ?
int health; // 生命值,越多越能打! ??
struct Equipment { // 裝備箱,裝滿了寶物! ??
std::string weapon; // 武器,打怪必備! ??
int damage; // 傷害值,越高越厲害! ??
} equip;
};
int main() {
// 第一種方式:傳統(tǒng)的一步步裝扮我們的英雄
// 就像是給洋娃娃換裝一樣,雖然啰嗦但也很溫馨呢~ ??
GameCharacter hero1;
hero1.name = "勇者小明"; // 給英雄起個(gè)響亮的名字! ??
hero1.health = 100; // 滿滿的生命值! ??
hero1.equip.weapon = "木劍"; // 新手村的標(biāo)配裝備~ ???
hero1.equip.damage = 10; // 攻擊力還不錯(cuò)哦! ?
// 第二種方式:聚合初始化 - 像變魔術(shù)一樣,一揮手就裝備齊全! ???
GameCharacter hero2 = {
"勇者小紅", // 這位英雄喜歡紅色! ??
100, // 同樣是滿血出發(fā)! ??
{ // 裝備時(shí)間到! ??
"鐵劍", // 升級(jí)裝備登場(chǎng)! ??
15 // 傷害提升啦! ??
}
};
// 第三種方式:C++20的指定初始化 - 最清晰的英雄登場(chǎng)方式!
// 就像給每件裝備都貼上了標(biāo)簽,再也不會(huì)搞混啦! ???
GameCharacter hero3 = {
.name = "勇者小藍(lán)", // 藍(lán)色系英雄駕到! ??
.health = 100, // 當(dāng)然也是滿血啦! ??
.equip = {
.weapon = "魔法杖", // 哇哦!法師裝備! ??
.damage = 20 // 魔法傷害最高! ?
}
};
}
瞧瞧,我們的三位英雄已經(jīng)準(zhǔn)備就緒,整裝待發(fā)啦! ?? 每個(gè)英雄都有自己獨(dú)特的裝扮方式,就像是在玩換裝游戲一樣有趣呢~ ?? 無(wú)論你喜歡哪種打扮方式,他們都是最棒的冒險(xiǎn)者! 讓我們一起期待他們精彩的冒險(xiǎn)故事吧! ?? ??
數(shù)組的聚合初始化 - 打開我們的百寶箱! ???
哎呀,數(shù)組的初始化就像是在整理我們的玩具箱呢! 想象一下,每個(gè)數(shù)字都是一個(gè)可愛(ài)的小玩偶,我們要把它們整整齊齊地排列好~ ??
// 一維數(shù)組就像是一列小火車,每個(gè)車廂都裝著一個(gè)寶貝! ??
int scores[] = {95, 88, 76}; // 嘟嘟嘟~三個(gè)小乘客已就座! ???
// 二維數(shù)組就像是一個(gè)魔法積木盒,每層都有不同的驚喜! ??
int matrix[2][3] = {
{1, 2, 3}, // 第一層的小精靈們 ??♀?
{4, 5, 6} // 第二層的小仙子們 ??♂?
};
// 字符數(shù)組簡(jiǎn)直就是魔法咒語(yǔ)啦!一句話就能召喚出一串小精靈! ?
char name[] = "Hello"; // 噔噔咚~五個(gè)字母小精靈排排站! ??
// 悄悄告訴你,這和 {'H','e','l','l','o','\0'} 是一樣的哦~
// 最后那個(gè)'\0'就像是給隊(duì)伍打上的一個(gè)可愛(ài)的小印章! ??
看看,是不是感覺(jué)數(shù)組變得超級(jí)有趣呢? 每個(gè)數(shù)字都像是一個(gè)調(diào)皮的小精靈,在我們的代碼世界里快樂(lè)地玩耍~ ?? 無(wú)論是排成一列的小火車,還是堆成小樓的積木,它們都在等著和我們一起創(chuàng)造編程的魔法! ??? 讓我們繼續(xù)這場(chǎng)奇妙的編程冒險(xiǎn)吧! ??
聚合初始化的小秘密 - 并不是所有類都能參加這場(chǎng)派對(duì)! ??
嘿,小伙伴們~ 在使用聚合初始化這個(gè)魔法之前,我們得先了解一下它的"小脾氣"呢! 就像挑食的小朋友一樣,它對(duì)類的結(jié)構(gòu)可是相當(dāng)挑剔的呢~ ??
// 瞧瞧這個(gè)害羞的結(jié)構(gòu)體,它把自己的小秘密藏起來(lái)啦! ??
struct Wrong {
private:
int x; // 這個(gè)小可愛(ài)躲在private后面,聚合初始化表示: "不跟你玩!" ??
};
// 這位結(jié)構(gòu)體太能干啦,自己就會(huì)打扮自己,
// 但聚合初始化說(shuō): "不用麻煩啦,讓我來(lái)幫你~"
// 結(jié)果發(fā)現(xiàn)幫不上忙... ??
struct AlsoWrong {
int x;
AlsoWrong() : x(0) {} // 有自己的構(gòu)造函數(shù),就像有了自己的主見(jiàn),不愿意讓別人幫忙啦! ??
};
// 這個(gè)結(jié)構(gòu)體想要變身,但聚合初始化說(shuō):
// "抱歉,我不會(huì)變身魔法!" ??♂?
struct StillWrong {
virtual void foo() {} // 虛函數(shù)就像是變身技能,但聚合初始化不懂這么高深的魔法! ?
int x;
};
所以啊,想要和聚合初始化這位魔法師成為好朋友,我們的類就要保持簡(jiǎn)單純真的本色 - 公開透明(public),不耍小聰明(沒(méi)有構(gòu)造函數(shù)),也不要玩變身游戲(不要虛函數(shù))。這樣它才會(huì)開心地幫我們打理好所有的初始化工作呢! ?? 就像是在魔法花園里,只有最單純的小花才能綻放出最美麗的光芒~ ?? ?
實(shí)用魔法大揭秘 - 讓代碼變得更優(yōu)雅吧! ???
哎呀,小伙伴們~讓我們來(lái)學(xué)習(xí)一些超級(jí)實(shí)用的魔法技巧吧! 這些招數(shù)可都是編程界的"明星法術(shù)"呢! ??
首先,讓我們認(rèn)識(shí)一下 std::array 這位可靠的小伙伴~ 它就像是給我們的數(shù)據(jù)穿上了一件防護(hù)服,比普通的數(shù)組要安全得多呢! ???
#include <array>
// 瞧瞧這個(gè)漂亮的小數(shù)組,多整齊啊! ??
std::array<int, 3> scores = {95, 88, 76}; // 就像三個(gè)并排站好的小學(xué)生! ??
// 哇哦,這個(gè)二維數(shù)組就像是一個(gè)魔方格子,每個(gè)格子都住著可愛(ài)的數(shù)字! ??
std::array<std::array<int, 2>, 3> grid = {{
{1, 2}, // 第一層的小可愛(ài)們 ??
{3, 4}, // 第二層的小精靈們 ??
{5, 6} // 第三層的小仙子們 ??♀?
}};
接下來(lái)是我們的積木游戲時(shí)間! 看看這些結(jié)構(gòu)體是怎么像搭積木一樣組合在一起的~ ???
struct Point { int x, y; }; // 這是我們的基礎(chǔ)積木塊! ??
struct Rectangle { // 用積木搭個(gè)小房子~ ??
Point topLeft; // 左上角,像房子的屋頂角 ??
Point bottomRight; // 右下角,像房子的地基角 ??
std::string color; // 給房子涂上漂亮的顏色! ??
};
// 瞧瞧這個(gè)漂亮的紅房子! ??
Rectangle rect = {
{0, 0}, // 頂部角落悄悄站好~ ??
{100, 100}, // 底部角落扎根在這里! ??
"紅色" // 刷上喜慶的紅色! ??
};
// 哇!C++20讓我們的房子更好看啦!
// 每個(gè)部分都貼上了名字標(biāo)簽,就像精品建筑一樣! ??
Rectangle rect2 = {
.topLeft = {.x = 0, .y = 0}, // 屋頂角精確定位! ??
.bottomRight = {.x = 100, .y = 100}, // 地基角完美落位! ??
.color = "藍(lán)色" // 換成清爽的藍(lán)色! ??
};
最后,讓我們來(lái)玩玩vector這個(gè)百變小精靈! 它就像是會(huì)自動(dòng)變長(zhǎng)的魔法口袋,想裝多少東西都可以! ??
#include <vector>
// 看看這些點(diǎn)點(diǎn),像天上的星星一樣閃亮! ?
std::vector<Point> points = {
{0, 0}, // 第一顆小星星 ??
{1, 1}, // 第二顆小星星 ?
{2, 2} // 第三顆小星星 ??
};
// 哇塞!這個(gè)矩陣就像是魔法棋盤,每個(gè)格子都藏著數(shù)字寶藏! ??
std::vector<std::vector<int>> matrix = {
{1, 2, 3}, // 第一排小寶貝們 ??
{4, 5, 6}, // 第二排小天使們 ??
{7, 8, 9} // 第三排小精靈們 ??
};
看!這些代碼是不是像施展魔法一樣有趣呀? 每個(gè)數(shù)據(jù)結(jié)構(gòu)都是我們的小伙伴,它們合作起來(lái)就能創(chuàng)造出無(wú)限的可能! 讓我們一起在代碼的世界里繼續(xù)探險(xiǎn)吧! ???
注意事項(xiàng)與常見(jiàn)陷阱 - 小心前方有坑哦! ??
哎呀,小伙伴們~在使用聚合初始化這個(gè)魔法時(shí),我們還得當(dāng)心一些調(diào)皮的小陷阱呢! 就像是在探險(xiǎn)時(shí)要小心躲避搗蛋的機(jī)關(guān)一樣~ ?? 讓我們一起來(lái)看看這些有趣的例子吧!
// 來(lái)看看這個(gè)可愛(ài)的小配置盒子 ??
struct Config {
std::string name; // 給它起個(gè)好聽(tīng)的名字 ???
int value = 42; // 這個(gè)神奇的數(shù)字是生命、宇宙和一切的答案! ??
};
// 哇哦,讓我們來(lái)玩?zhèn)€初始化的小游戲吧! ??
Config c1 = {"測(cè)試"}; // 嘿嘿,value偷偷用了默認(rèn)值42,它害羞不想出來(lái)啦! ??
Config c2 = {}; // 空空如也~但是value還是悄悄地保持著42哦! ?
Config c3 = {.name="測(cè)試"}; // C++20的新玩法,給name貼上小標(biāo)簽,value繼續(xù)當(dāng)隱形人! ??
// 但是要小心這個(gè)搗蛋鬼結(jié)構(gòu)體哦! 它可藏著小秘密呢~ ??
struct Tricky {
int a; // 第一個(gè)小精靈 ??
int b = 1; // 第二個(gè)帶著默認(rèn)值的小精靈 ??♀?
int c; // 第三個(gè)調(diào)皮的小精靈 ??♂?
};
// 噔噔咚!神奇的事情發(fā)生啦! ?
Tricky t = {42}; // 哎呀呀,發(fā)生了什么?
// a高高興興地得到了42 ??
// b保持著自己的1不變 ??
// c偷偷溜進(jìn)去個(gè)0,真是個(gè)搗蛋鬼! ??
瞧瞧,這些小陷阱是不是像躲貓貓一樣有趣呀? ?? 它們提醒我們?cè)谑褂镁酆铣跏蓟@個(gè)強(qiáng)大的魔法時(shí),要睜大眼睛觀察每個(gè)小細(xì)節(jié)。就像在魔法學(xué)校上課一樣,每個(gè)咒語(yǔ)都要念得清清楚楚,不然可能會(huì)召喚出意想不到的小驚喜呢! ???
記住啦,默認(rèn)值就像是會(huì)隱身的小精靈,而未初始化的成員則會(huì)悄悄變成0,就像施了個(gè)清零魔法一樣! 讓我們?cè)诰幊痰钠婷钍澜缋锢^續(xù)探險(xiǎn)吧!