zoukankan      html  css  js  c++  java
  • 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 初始化列表并不能指定初始化的顺序,正确的顺序是,首先初始化基类,其次根据派生类成员声明次序依次初始化。

  • 相关阅读:
    随机发牌 代码
    网络传输 buf 封装 示例代码
    简易数据库实现 UNIX环境高级编程(APUE)第二十章 A Database Library
    状态机学习(六)解析JSON2
    又一篇四则运算代码
    c++ stl源码剖析学习笔记(三)容器 vector
    c++ stl源码剖析学习笔记(二)iterator
    Linux系统编程(16)——正则表达式入门
    Linux系统编程(15)——shell脚本语法
    Linux系统编程(14)——shell常用命令
  • 原文地址:https://www.cnblogs.com/lei-zi/p/11121187.html
Copyright © 2011-2022 走看看