C++构造函数初始化列表

构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用初始化列表。

C++构造函数的初始化列表使得代码更加简洁,请看下面的例子:

arduino 复制代码
    #include <iostream>
    using namespace std;
    class Student{
    private:
        char *m_name;
        int m_age;
        float m_score;
    public:
        Student(char *name, int age, float score);
        void show();
    };
    //采用初始化列表
    Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
        //TODO:
    }
    void Student::show(){
        cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
    }
    int main(){
        Student stu("小明", 15, 92.5f);
        stu.show();
        Student *pstu = new Student("李华", 16, 96);
        pstu -> show();
        return 0;
    }

运行结果:小明的年龄是15,成绩是92.5李华的年龄是16,成绩是96

如本例所示,定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号:,后面紧跟m_name(name), m_age(age), m_score(score)语句,这个语句的意思相当于函数体内部的m_name = name; m_age = age; m_score = score;语句,也是赋值的意思。

使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便,尤其是成员变量较多时,这种写法非常简单明了。初始化列表可以用于全部成员变量,也可以只用于部分成员变量。下面的示例只对 m_name 使用初始化列表,其他成员变量还是一一赋值:

ini 复制代码
    Student::Student(char *name, int age, float score): m_name(name){
        m_age = age;
        m_score = score;
    }

注意,成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关。请看代码:

arduino 复制代码
    #include <iostream>
    using namespace std;
    class Demo{
    private:
        int m_a;
        int m_b;
    public:
        Demo(int b);
        void show();
    };
    Demo::Demo(int b): m_b(b), m_a(m_b){ }
    void Demo::show(){ cout<<m_a<<", "<<m_b<<endl; }
    int main(){
        Demo obj(100);
        obj.show();
        return 0;
    }

运行结果:2130567168, 100

在初始化列表中,我们将 m_b 放在了 m_a 的前面,看起来是先给 m_b 赋值,再给 m_a 赋值,其实不然!成员变量的赋值顺序由它们在类中的声明顺序决定,在 Demo 类中,我们先声明的 m_a,再声明的 m_b,所以构造函数和下面的代码等价:

ini 复制代码
    Demo::Demo(int b): m_b(b), m_a(m_b){
        m_a = m_b;
        m_b = b;
    }

给 m_a 赋值时,m_b 还未被初始化,它的值是不确定的,所以输出的 m_a 的值是一个奇怪的数字;给 m_a 赋值完成后才给 m_b 赋值,此时 m_b 的值才是 100。

obj 在栈上分配内存,成员变量的初始值是不确定的。

初始化 const 成员变量

构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。例如 VS/VC 不支持变长数组(数组长度不能是变量),我们自己定义了一个 VLA 类,用于模拟变长数组,请看下面的代码:

arduino 复制代码
    class VLA{
    private:
        const int m_len;
        int *m_arr;
    public:
        VLA(int len);
    };
    //必须使用初始化列表来初始化 m_len
    VLA::VLA(int len): m_len(len){
        m_arr = new int[len];
    }

VLA 类包含了两个成员变量,m_len 和 m_arr 指针,需要注意的是 m_len 加了 const 修饰,只能使用初始化列表的方式赋值,如果写作下面的形式是错误的:

arduino 复制代码
    class VLA{
    private:
        const int m_len;
        int *m_arr;
    public:
        VLA(int len);
    };
    VLA::VLA(int len){
        m_len = len;
        m_arr = new int[len];
    }
相关推荐
愤怒火龙果10 小时前
AI 渗透测试智能体架构综述:从单兵到蜂群的演进图谱
人工智能·网络安全·架构
Oiiouui10 小时前
Godot-GridGame架构逻辑层与实体/物品层篇
架构·游戏引擎·godot
涛声依旧-底层原理研究所11 小时前
Agent 沙箱实现原理:拆解 DeepSeek Harness 的三层沙箱架构与三平台后端
人工智能·架构
tianyuanwo11 小时前
Prometheus 服务部署指南:从架构原理到生产级落地
架构·prometheus
Rain的Java大神之路11 小时前
北漂 13 年,我把 Java 家底钉成了这张知识图谱(全站免费)
java·后端·程序员
尤水就下11 小时前
🔥说一说在线文档的 Block 架构是如何实现的
前端·javascript·架构
深圳老胡11 小时前
FDC2212 + STM32G030 液面探测:IIC 读数跳动导致下探深度不一致的排查与解决
笔记·stm32·单片机·代码规范·1024程序员节
代码方舟11 小时前
零信任架构实战:基于天远企业二要素验证构建自动化小微快贷法人资质核验网关
运维·人工智能·架构·自动化
代码山河12 小时前
调试技巧:IDEA Debug模式入门与使用
java·学习·架构·教程·面向对象·项目
2601_9687080312 小时前
DreamsChat Web – Chat, Audio, Video Web APP with Admin Dashboard
前端·架构