• C++初始化列表


    原文:https://zhuanlan.zhihu.com/p/33004628

    下面我们先看例子

     1 #include <iostream>
     2 using namespace std;
     3 class Base
     4 {
     5 public:
     6     Base(int val)
     7    {
     8        m_num = 0;
     9         cout << "create Base(int val)" << endl;
    10     }
    11 private:
    12     int m_num;
    13 };

    上边的代码,我先定义了一个Base类,并且定义了有一个整型实参的构造函数Base(int val)

     

     1 class BaseChild: public Base
     2 {
     3 public:
     4     BaseChild()
     5     {
     6         m_num = 0;
     7         cout << "create is BaseChild()" << endl;
     8     }
     9 
    10 private:
    11     int m_num;
    12 };
    13 
    14 int main(int argc, char *argv[])
    15 {
    16     BaseChild child;
    17 }

    上边的代码继承Base,定义了它的默认构造函数

    并且在主函数中创建BaseChild的对象child

    编译但报如下错误:

     

     

    这意思是说,没有Base的默认构造函数。

     

    结论1:如果没有定义任何构造函数,C++编译器会自动创建一个默认构造函数。
    结论2:如果已经定义了一个构造函数,编译器不会自动创建默认构造函数,只能显式调用该构造函数。

     

    在C++中,当创建一个对象时,编译器要保证调用了所有子对象的构造函数,这是C++强制要求的,也是它的一个机制。

     

    因为在Base中没有定义默认构造函数,只定义了一个有整型参数的构造函数,因此编译器并不会再去生成一个默认的构造函数,而BaseChild继承Base时,又没有显式地指定Base的构造函数,所以编译报错。

     

    如果我们不修改Base,那么,我们用什么办法不去调用默认构造函数,而是显式的调用Base带参构造函数呢。答案就是初始化列表。

     

    C++就为我们提供了这样的语法。即在冒号和这个构造函数定义体的左括号之间可指定基类构造函数,如下:

    1 BaseChild():Base(1)
    2 {
    3     cout << "create is BaseChild()" << endl;
    4 }

    现在,再编译程序,轻松通过。

     

    当然,初始化列表还可以对类本身的数据成员进行初始化,如对BaseChild成员m_num进行初始化:

     1 BaseChild():Base(1), m_num(0){...} 
    

    中间要以逗号隔开。

     

    细心的同学,可能会提问,我们平常见到的都是

    int m_num = 0;

    而刚刚的代码是m_num(0),这是正确的,我们可以认为这就是调用了int类型的构造函数。类似的,new int(2)是一样的道理。

     

    上面是整数类型的赋值,那么,如果是对象之间的赋值呢,例如:

    BaseChild child = BaseChild();

    其实,这又涉及了另外一个话题,赋值构造函数和编译器的优化。

    其具体执行顺序是:

    1调用BaseChild构造函数,生成一个临时对象

    2给child成员赋值

    3创建child对象后,删除临时对象

    那么,针对上面的顺序,编译器有可能会优化代码为BaseChild child()直接创建child对象。

     

    最后,总结一下初始化列表吧:

    1 因为初始化列表中无法直接初始化基类的数据成员,所以你需要在列表中指定基类的构造函数,如果不指定,编译器则会调用基类的默认构造函数。

     

    2 推荐使用初始化列表,它会比在函数体内初始化派生类成员更快,这是因为在分配内存后,在函数体内又多进行了一次赋值操作。

     

    3 初始化列表并不能指定初始化的顺序,正确的顺序是,首先初始化基类,其次根据派生类成员声明次序依次初始化。

  • 相关阅读:
    python经典算法面试题1.5:如何找出单链表中的倒数第K个元素
    python经典面试算法题1.4:如何对链表进行重新排序
    巧妙利用引用,将数组转换成树形数组
    设计模式学习笔记
    Vue-cli项目部署到Nginx
    设计模式
    设计模式
    springboot原理
    类加载机制-深入理解jvm
    JVM内存调优原则及几种JVM内存调优方法
  • 原文地址:https://www.cnblogs.com/lei-zi/p/11121187.html
Copyright © 2020-2023  润新知