• C++基础——初始化列表


    目录

    一.初始化列表

    1.列表格式:

    情况1: 成员变量中有const成员—— 但列表处成员不被初始化时

    情况1: 成员变量中有const成员—— 给缺省值时:

     情况1: 成员变量中有const成员—— 列表处成员不仅初始化,还有缺省值

    情况2:成员是自定义类型成员时:

    优化方案1:使得类A有默认构造

     优化方案2:采用初始化列表

    总结:


    一.初始化列表


            虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。采用从初始化列表的缘故是因为成员变量中会存在一些特殊情况,只能由初始化列表去赋值。

    1.列表格式:

            以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟
    一个放在括号中的初始值或表达式。
     

    自定义类型 类型名(    )   

            :  成员变量1 (赋值)

            ,  成员变量2 (赋值)

            ,  成员变量3 (赋值)

            ......

            {

            //构造函数内部......

            }

    【注意】:

    1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

    例,代码如下:

    1. class Date
    2. {
    3. public:
    4. //构造函数
    5. Date(int year, int month, int day)
    6. //初始化列表
    7. :_year(1999)
    8. ,_month(10)
    9. ,_day(30)
    10. {
    11. _year = year;
    12. _month = month;
    13. _day = day;
    14. }
    15. void Print()
    16. {
    17. cout << "Print()" << endl;
    18. cout << "year:" << _year << endl;
    19. cout << "month:" << _month << endl;
    20. cout << "day:" << _day << endl << endl;
    21. }
    22. private:
    23. int _year; // 年
    24. int _month; // 月
    25. int _day; // 日
    26. };
    27. int main(){
    28. Date d1;
    29. }

            当创建对象d1时,调用该类构造函数,在进入构造函数前,各成员变量都是随机值,编译器会先进入初始化列表,为各成员变量初始化值。

    例2:Stack类初始化列表:

    1. typedef int DataType;
    2. class Stack
    3. {
    4. public:
    5. Stack(size_t capa)
    6. //初始化列表
    7. :_size(0)
    8. , _capacity(capa)
    9. , _array((DataType*)malloc(capa * sizeof(DataType)))
    10. {
    11. //构造函数内部
    12. if (nullptr == _array)
    13. {
    14. perror("malloc申请空间失败");
    15. return;
    16. }
    17. }
    18. void Push(const DataType& data)
    19. {
    20. // CheckCapacity();
    21. _array[_size] = data;
    22. _size++;
    23. }
    24. ~Stack()
    25. {
    26. if (_array)
    27. {
    28. free(_array);
    29. _array = nullptr;
    30. _capacity = 0;
    31. _size = 0;
    32. }
    33. }
    34. private:
    35. DataType* _array;
    36. size_t _size;
    37. size_t _capacity;
    38. };

            也可以将构造函数和初始化列表混合着用:

    1. typedef int DataType;
    2. class Stack
    3. {
    4. public:
    5. Stack(size_t capa)
    6. :_size(0)
    7. , _capacity(capa)
    8. {
    9. //构造函数内部
    10. _array =(DataType*)malloc(capa * sizeof(DataType));
    11. if (nullptr == _array)
    12. {
    13. perror("malloc申请空间失败");
    14. return;
    15. }
    16. }

            在初始化列表中先初始化size和capacity,针对于指针开辟空间的成员还是放在构造函数内部好,因为要与判断相连接,还是混着来比较好。

    初始化列表最重要的作用就是为特殊的成员变量提供初始化帮助: 

     2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

            引用成员变量

            const成员变量

            自定义类型成员(且该类没有默认构造函数时) 

            当我们在定义const变量时,往往需要定义时就要给初始化值:

             而构造函数并不能满足需求,需要用到初始化列表。

    情况1: 成员变量中有const成员—— 但列表处成员不被初始化时

    1. class B{
    2. public:
    3. B()
    4. :_n(10) //初始化列表
    5. {}
    6. private:
    7. const int _n; // const
    8. int _m;
    9. };

     

            总结:每个成员都要走初始化列表,就是成员没有在初始化列表写,也会走。但初始化列表只有_n被初始化,而_m没有,所以赋给随机值 

    情况1: 成员变量中有const成员—— 给缺省值时:

    1. class B
    2. {
    3. public:
    4. B()
    5. :_n(10) //初始化列表
    6. {}
    7. private:
    8. const int _n; // const
    9. int _m=1; //缺省值
    10. };
    11. int main() {
    12. B b2;
    13. }

            总结:因为成员变量处给了缺省值,但此时_m还处于随机值,直到运行时编译器进入构造函数初始化列表,_m才会使用缺省值 

     情况1: 成员变量中有const成员—— 列表处成员不仅初始化,还有缺省值

    1. class B
    2. {
    3. public:
    4. B(int a, int ref)
    5. :_n(10) //初始化列表
    6. , _m(3)
    7. {}
    8. private:
    9. const int _n; // const
    10. int _m=100; //缺省值
    11. };

            总结:这次,_m不仅有缺省值,还在初始化列表中被初始化,而编译器会优先选择初始化列表的值初始化列表使用权>缺省值使用权限,所以最终_m最终是按照初始化列表的赋值使用,其值为3。


    情况2:成员是自定义类型成员时:

    1. class A{
    2. public:
    3. //构造函数,并不是默认构造
    4. A(int a)
    5. :_a(a)
    6. {}
    7. private:
    8. int _a;
    9. };
    10. class B{
    11. public:
    12. B()
    13. :_n(10) //初始化列表
    14. {}
    15. private:
    16. const int _n; // const
    17. A _aa;
    18. };
    19. int main() {
    20. B b4;
    21. }

           总结:编译器执行对象b4的创建时,会进入类B的构造函数,因为成员变量有自定义类型 _aa,所以编译器会进入类A中找它的默认构造,但类A中没有默认构造,类A中只有自己写的构造函数,此时也就无法给自定义类型成员_aa赋值,所以编译器会报错。  

    优化方案1:使得类A有默认构造函数(这个默认构造可以是全缺省的构造函数,也可以是无参构造,或者直接不写由编译器自动生成的构造函数)

            编译器运行正常,自定义类型成员变量_aa赋值为10,const成员变量_n初始化值为10。

     优化方案2:让类A放弃默认构造,采用初始化列表

    1. class A{
    2. public:
    3. //不采用默认构造,但初始化列表给值了也不会报错
    4. A(int a )
    5. :_a(a)
    6. {}
    7. private:
    8. int _a;
    9. };
    10. class B{
    11. public:
    12. B()
    13. :_n(10) //初始化列表
    14. ,_aa(75)
    15. {}
    16. private:
    17. const int _n; // const
    18. A _aa;
    19. };
    20. int main() {
    21. B b;
    22. return 0;
    23. }

            调用b的成员时,即调用A _aa时会到A类中调用它的默认构造,没有默认构造时,使用初始化列表,也不会报错。 

            对于引用成员来说,它与const一样,都是需要在定义时就得初始化,而采用构造函数并不能满足需求,只能使用初始化列表。


    总结:

          1. 对于内置类型,没有成员在初始化列表中显示时,有缺省值就使用缺省值,没有缺省值就只能是随机值。
           2.对于自定义类型,调用它的默认构造函数,若没有默认构造函数,则报错!!!
           3.默认构造三种形式:无参构造、全缺省构造、不亲自写编译器自己生成的默认构造。

           4.要尽量使用初始化列表去初始化成员变量(因为有const、自定义类型、引用)。

           5.尽量提供默认构造函数(推荐:全缺省)。

     

  • 相关阅读:
    Jetpack Compose基础组件之 — Text
    七、Request&Response
    用Spring Cloud Alibaba构建用户中心!只要5分钟
    Python进阶:反射
    万字长文才把大型网站架构的技术细节:前端架构规整化手段讲明白
    如何获取springboot中所有的bean
    子组件和父组件数据双向绑定
    Next.js多页布局getLayout使用方法
    辅助驾驶功能开发-功能对标篇(13)-NOA领航辅助系统-长安
    Day-04 从 0 开始搭建一套规范的 Vue3.x 项目工程环境
  • 原文地址:https://blog.csdn.net/weixin_69283129/article/details/127809697