初始化代码写到崩溃?这个 C++ 魔法必须安排上!

开发
现在的聚合初始化就像是一位温柔又可靠的管家,帮我们把所有的初始化工作都打理得妥妥当当的。无论是简单的数组、结构体,还是复杂的嵌套类型,它都能轻松应对!

大家好啊! 👋 我是 everystep,今天让我们来聊聊 C++ 中的聚合初始化这个有趣的话题。不过在开始之前,让我们先来听听这个魔法特性的小故事~

很久很久以前(其实也就是 C++98 的年代啦 😉),程序员们在初始化变量时可是遇到了不少烦恼呢。那时候的初始化就像是一场混乱的舞会 🎭,大家都在用着不同的方式跳舞:有人喜欢用圆括号(),有人偏爱等号=,还有人钟情于花括号{}。这可让代码世界乱成一锅粥啦! 🥘

直到有一天,C++11 的标准委员会决定要给这场舞会定下新规则。他们说:"让我们创造一个统一的初始化方式吧!" 于是,聚合初始化这个可爱的小精灵就诞生啦! 🧚♀️ 它不仅统一了初始化的语法,还带来了很多意想不到的惊喜呢~

比如说,它可以防止类型收窄(narrowing),就像是给我们的数据穿上了一件防护服 🛡️。如果你试图把一个 double 偷偷塞进 int 里面,它就会大声说"不行!" 这可帮助我们避免了很多调皮的 bug 呢! 🐞

到了 C++17,这个小精灵又学会了新魔法,它可以在嵌套初始化时省略一些烦人的花括号,让代码看起来更整洁啦! ✨ 而在 C++20 中,它更是学会了给每个值都贴上标签的本领,这下再也不会认错谁是谁啦! 🏷️

现在的聚合初始化就像是一位温柔又可靠的管家,帮我们把所有的初始化工作都打理得妥妥当当的。无论是简单的数组、结构体,还是复杂的嵌套类型,它都能轻松应对! 🎩✨

基本语法 - 让我们开始这场魔法表演吧! 🎩✨

// 瞧瞧这个最基础的写法,就像魔术师挥舞魔法棒 "噔噔咚~" ✨
// 所有的值都乖乖排好队,准备入住它们的新家啦! 🏠
T object = { arg1, arg2, ... };  

// C++11 来了个小改良,连等号都省掉啦! 
// 就像快递直接送到家,完全不用签收 📦💨
T object { arg1, arg2, ... };    

// 到了C++20,简直就像给每个小可爱都贴上了名牌! 
// 再也不会认错谁是谁啦 🎀
// 就像幼儿园小朋友的书包和水杯,每个都有自己的标签 🏷️
T object = { .name = "小明", .age = 18 };  // 多可爱呀! 🌟

瞧瞧,这些初始化方式就像是在变魔术一样神奇,对吧? 🪄 每种方式都有它自己的小特色,就像是不同口味的糖果,你最喜欢哪一种呢? 🍬 无论选择哪种方式,它们都会帮我们把数据整整齐齐地收拾好,就像是给玩具找到了完美的收纳盒! 🎪✨

来看个有趣的例子 - 打造我们的小小冒险世界! 🎮 🌈

想象一下,我们正在创造一个充满魔法的游戏世界,需要召唤一些勇敢的小英雄来拯救世界~ 让我们看看如何给这些可爱的勇者们安排他们的冒险装备吧! 🧙♂️✨

// 这就是我们勇者的基本配置单,就像是英雄的简历表一样! 📝
struct GameCharacter {
    std::string name;      // 英雄的闪亮名字 ⭐
    int health;           // 生命值,越多越能打! 💖
    struct Equipment {    // 装备箱,装满了宝物! 🎁
        std::string weapon;  // 武器,打怪必备! ⚔️
        int damage;         // 伤害值,越高越厉害! 💥
    } equip;
};

int main() {
    // 第一种方式:传统的一步步装扮我们的英雄
    // 就像是给洋娃娃换装一样,虽然啰嗦但也很温馨呢~ 👗
    GameCharacter hero1;
    hero1.name = "勇者小明";      // 给英雄起个响亮的名字! 📣
    hero1.health = 100;          // 满满的生命值! 💝
    hero1.equip.weapon = "木剑";  // 新手村的标配装备~ 🗡️
    hero1.equip.damage = 10;     // 攻击力还不错哦! ⚡

    // 第二种方式:聚合初始化 - 像变魔术一样,一挥手就装备齐全! 🎩✨
    GameCharacter hero2 = {
        "勇者小红",     // 这位英雄喜欢红色! ❤️
        100,           // 同样是满血出发! 💗
        {              // 装备时间到! 🎵
            "铁剑",    // 升级装备登场! ⚔️
            15         // 伤害提升啦! 💫
        }
    };

    // 第三种方式:C++20的指定初始化 - 最清晰的英雄登场方式! 
    // 就像给每件装备都贴上了标签,再也不会搞混啦! 🏷️
    GameCharacter hero3 = {
        .name = "勇者小蓝",      // 蓝色系英雄驾到! 💙
        .health = 100,          // 当然也是满血啦! 💖
        .equip = {
            .weapon = "魔法杖",  // 哇哦!法师装备! 🔮
            .damage = 20        // 魔法伤害最高! ✨
        }
    };
}

瞧瞧,我们的三位英雄已经准备就绪,整装待发啦! 🚀 每个英雄都有自己独特的装扮方式,就像是在玩换装游戏一样有趣呢~ 🎭 无论你喜欢哪种打扮方式,他们都是最棒的冒险者! 让我们一起期待他们精彩的冒险故事吧! 🌟 🎉

数组的聚合初始化 - 打开我们的百宝箱! 🎁✨

哎呀,数组的初始化就像是在整理我们的玩具箱呢! 想象一下,每个数字都是一个可爱的小玩偶,我们要把它们整整齐齐地排列好~ 🧸

// 一维数组就像是一列小火车,每个车厢都装着一个宝贝! 🚂
int scores[] = {95, 88, 76};  // 嘟嘟嘟~三个小乘客已就座! 🎟️

// 二维数组就像是一个魔法积木盒,每层都有不同的惊喜! 🎪
int matrix[2][3] = {
    {1, 2, 3},  // 第一层的小精灵们 🧚♀️
    {4, 5, 6}   // 第二层的小仙子们 🧚♂️
};

// 字符数组简直就是魔法咒语啦!一句话就能召唤出一串小精灵! ✨
char name[] = "Hello";  // 噔噔咚~五个字母小精灵排排站! 🌟
// 悄悄告诉你,这和 {'H','e','l','l','o','\0'} 是一样的哦~
// 最后那个'\0'就像是给队伍打上的一个可爱的小印章! 💫

看看,是不是感觉数组变得超级有趣呢? 每个数字都像是一个调皮的小精灵,在我们的代码世界里快乐地玩耍~ 🎠 无论是排成一列的小火车,还是堆成小楼的积木,它们都在等着和我们一起创造编程的魔法! 🎪✨ 让我们继续这场奇妙的编程冒险吧! 🚀

聚合初始化的小秘密 - 并不是所有类都能参加这场派对! 🎭

嘿,小伙伴们~ 在使用聚合初始化这个魔法之前,我们得先了解一下它的"小脾气"呢! 就像挑食的小朋友一样,它对类的结构可是相当挑剔的呢~ 🤔

// 瞧瞧这个害羞的结构体,它把自己的小秘密藏起来啦! 🙈
struct Wrong {
private:
    int x;  // 这个小可爱躲在private后面,聚合初始化表示: "不跟你玩!" 🚫
};

// 这位结构体太能干啦,自己就会打扮自己,
// 但聚合初始化说: "不用麻烦啦,让我来帮你~" 
// 结果发现帮不上忙... 😅
struct AlsoWrong {
    int x;
    AlsoWrong() : x(0) {}  // 有自己的构造函数,就像有了自己的主见,不愿意让别人帮忙啦! 🎀
};

// 这个结构体想要变身,但聚合初始化说:
// "抱歉,我不会变身魔法!" 🦹♂️
struct StillWrong {
    virtual void foo() {}  // 虚函数就像是变身技能,但聚合初始化不懂这么高深的魔法! ✨
    int x;
};

所以啊,想要和聚合初始化这位魔法师成为好朋友,我们的类就要保持简单纯真的本色 - 公开透明(public),不耍小聪明(没有构造函数),也不要玩变身游戏(不要虚函数)。这样它才会开心地帮我们打理好所有的初始化工作呢! 🌟 就像是在魔法花园里,只有最单纯的小花才能绽放出最美丽的光芒~ 🌸 ✨

实用魔法大揭秘 - 让代码变得更优雅吧! 🎩✨

哎呀,小伙伴们~让我们来学习一些超级实用的魔法技巧吧! 这些招数可都是编程界的"明星法术"呢! 🌟

首先,让我们认识一下 std::array 这位可靠的小伙伴~ 它就像是给我们的数据穿上了一件防护服,比普通的数组要安全得多呢! 🛡️

#include <array>

// 瞧瞧这个漂亮的小数组,多整齐啊! 📚
std::array<int, 3> scores = {95, 88, 76};  // 就像三个并排站好的小学生! 🎒

// 哇哦,这个二维数组就像是一个魔方格子,每个格子都住着可爱的数字! 🎲
std::array<std::array<int, 2>, 3> grid = {{
    {1, 2},  // 第一层的小可爱们 🎈
    {3, 4},  // 第二层的小精灵们 🎪
    {5, 6}   // 第三层的小仙子们 🧚♀️
}};

接下来是我们的积木游戏时间! 看看这些结构体是怎么像搭积木一样组合在一起的~ 🏗️

struct Point { int x, y; };  // 这是我们的基础积木块! 🧱
struct Rectangle {          // 用积木搭个小房子~ 🏠
    Point topLeft;         // 左上角,像房子的屋顶角 📍
    Point bottomRight;     // 右下角,像房子的地基角 📌
    std::string color;     // 给房子涂上漂亮的颜色! 🎨
};

// 瞧瞧这个漂亮的红房子! 🏮
Rectangle rect = {
    {0, 0},      // 顶部角落悄悄站好~ 👆
    {100, 100},  // 底部角落扎根在这里! 👇
    "红色"       // 刷上喜庆的红色! ❤️
};

// 哇!C++20让我们的房子更好看啦! 
// 每个部分都贴上了名字标签,就像精品建筑一样! 🏰
Rectangle rect2 = {
    .topLeft = {.x = 0, .y = 0},         // 屋顶角精确定位! 📐
    .bottomRight = {.x = 100, .y = 100}, // 地基角完美落位! 📏
    .color = "蓝色"                      // 换成清爽的蓝色! 💙
};

最后,让我们来玩玩vector这个百变小精灵! 它就像是会自动变长的魔法口袋,想装多少东西都可以! 🎪

#include <vector>

// 看看这些点点,像天上的星星一样闪亮! ✨
std::vector<Point> points = {
    {0, 0},  // 第一颗小星星 🌟
    {1, 1},  // 第二颗小星星 ⭐
    {2, 2}   // 第三颗小星星 💫
};

// 哇塞!这个矩阵就像是魔法棋盘,每个格子都藏着数字宝藏! 🎲
std::vector<std::vector<int>> matrix = {
    {1, 2, 3},  // 第一排小宝贝们 🎯
    {4, 5, 6},  // 第二排小天使们 🎪
    {7, 8, 9}   // 第三排小精灵们 🎭
};

看!这些代码是不是像施展魔法一样有趣呀? 每个数据结构都是我们的小伙伴,它们合作起来就能创造出无限的可能! 让我们一起在代码的世界里继续探险吧! 🚀✨

注意事项与常见陷阱 - 小心前方有坑哦! 🚧

哎呀,小伙伴们~在使用聚合初始化这个魔法时,我们还得当心一些调皮的小陷阱呢! 就像是在探险时要小心躲避捣蛋的机关一样~ 🎪 让我们一起来看看这些有趣的例子吧!

// 来看看这个可爱的小配置盒子 📦
struct Config {
    std::string name;     // 给它起个好听的名字 🏷️
    int value = 42;       // 这个神奇的数字是生命、宇宙和一切的答案! 🌌
};

// 哇哦,让我们来玩个初始化的小游戏吧! 🎮
Config c1 = {"测试"};     // 嘿嘿,value偷偷用了默认值42,它害羞不想出来啦! 🙈
Config c2 = {};          // 空空如也~但是value还是悄悄地保持着42哦! ✨
Config c3 = {.name="测试"}; // C++20的新玩法,给name贴上小标签,value继续当隐形人! 🎭

// 但是要小心这个捣蛋鬼结构体哦! 它可藏着小秘密呢~ 🎪
struct Tricky {
    int a;              // 第一个小精灵 🧚
    int b = 1;          // 第二个带着默认值的小精灵 🧚♀️
    int c;              // 第三个调皮的小精灵 🧚♂️
};

// 噔噔咚!神奇的事情发生啦! ✨
Tricky t = {42};  // 哎呀呀,发生了什么?
                  // a高高兴兴地得到了42 🎈
                  // b保持着自己的1不变 🎪
                  // c偷偷溜进去个0,真是个捣蛋鬼! 🙊

瞧瞧,这些小陷阱是不是像躲猫猫一样有趣呀? 🎭 它们提醒我们在使用聚合初始化这个强大的魔法时,要睁大眼睛观察每个小细节。就像在魔法学校上课一样,每个咒语都要念得清清楚楚,不然可能会召唤出意想不到的小惊喜呢! 🎩✨

记住啦,默认值就像是会隐身的小精灵,而未初始化的成员则会悄悄变成0,就像施了个清零魔法一样! 让我们在编程的奇妙世界里继续探险吧! 

责任编辑:赵宁宁 来源: everystep
相关推荐

2023-11-12 23:08:17

C++初始化

2010-02-06 14:40:50

C++初始化和赋值

2010-02-01 14:21:24

C++初始化列表

2010-02-06 15:58:10

C++集合初始化

2010-02-05 17:16:05

C++构造函数

2024-03-13 08:52:43

C++初始化方式

2011-06-09 14:13:06

C++JAVA缺省初始化

2023-10-06 20:57:52

C++聚合成员

2010-02-03 11:01:18

C++类静态成员初始化

2019-11-26 09:05:32

Python机器学习深度学习

2023-12-04 10:57:52

函数C++

2009-09-18 11:15:52

C#数组初始化

2009-07-31 17:51:27

C#对象初始化

2011-06-17 15:29:44

C#对象初始化器集合初始化器

2024-08-08 16:34:16

C++11编程

2024-08-26 15:06:20

2021-06-09 09:49:35

C++RAII语言

2020-10-12 09:49:14

C++ 开发代码

2010-02-06 10:24:48

C++二维数组初始化

2009-09-17 16:06:22

C#数组初始化
点赞
收藏

51CTO技术栈公众号