每日一面——成员初始化列表、移动构造和拷贝构造

本文详细讨论了C++中类成员的初始化方式,包括构造函数执行顺序、成员初始化列表的优势、final和override关键字的作用、拷贝初始化与直接初始化的区别、必须使用成员初始化的情况以及拷贝构造函数和移动构造函数的触发条件和影响。
摘要由CSDN通过智能技术生成

写前声明:参考链接 C++面经面试宝典

✊✊✊每日一面——成员初始化列表、移动构造和拷贝构造

    • 一、类成员初始化方式?构造函数的执行顺序?为什么用成员初始化列表会快一些?
    • 二、final和override关键字
    • 三、拷贝初始化和直接初始化
    • 四、有哪些情况必须用到成员列表初始化?作用是什么?
    • 五、什么情况下会调用拷贝构造函数?
    • 六、拷贝构造函数如果用值传递会有什么影响?
    • 七、说一说了解的移动构造函数?

一、类成员初始化方式?构造函数的执行顺序?为什么用成员初始化列表会快一些?

  • 赋值初始化, 通过在函数体内仅赋值初始化
  • 列表初始化,在冒号后使用初始化列表进行初始化

两种初始化的区别:

  • 对于在函数体中初始化,是在所有的数据成员被分配内存空间后才进行的
  • 列表初始化是给数据成员分配内存空间时就进行初始化,也就是说分配一个数据成员只要冒号后有此数据成员的赋值表达式(此表达式必须是括号赋值表达式),那么分配了内存空间后在进入函数体之前就给数据成员赋值了,即此时初始化数据成员时,函数体还未执行

一个派生类构造函数的执行顺序:

  1. 虚基类的构造函数(多个虚基类则按照继承的顺序执行构造函数)
  2. 基类的构造函数(多个普通基类也按照继承的顺序执行构造函数)
  3. 类类型的成员对象的构造函数(按照初始化顺序)
  4. 派生类自己的构造函数

法一是在构造函数中做赋值的操作,法二是纯粹的初始化操作。我们知道C++的赋值操作是会产生临时对象的,临时对象的出现会降低程序运行的效率

二、final和override关键字

override: 指定了子类这个虚函数是重写父类的
final: 当不希望某个类被继承,或不希望某个虚函数被重写,可以在类名和虚函数后添加final关键字

三、拷贝初始化和直接初始化

当用于类类型对象时,初始化的拷贝形式和直接形式有所不同:直接初始化会直接调用于实参匹配的构造函数,而拷贝初始化总是调用拷贝构造函数。拷贝初始化首先使用指定构造函数创建一个临时对象,然后用拷贝构造函数将那个临时对象拷贝到正在创建的对象。

四、有哪些情况必须用到成员列表初始化?作用是什么?

  • 必须使用成员初始化的四种情况

    • 当初始化一个引用成员时;

    • 当初始化一个常量成员时;

    • 当调用一个基类的构造函数,而它拥有一组参数时;

    • 当调用一个成员类的构造函数,而它拥有一组参数时;

  • 成员初始化列表做了什么

    • 编译器会一一操作初始化列表,以适当的顺序在构造函数之内安插初始化操作,并且在任何显示用户代码之前;

    • ist中的项目顺序是由类中的成员声明顺序决定的,不是由初始化列表的顺序决定的;

五、什么情况下会调用拷贝构造函数?

  • 用类的一个实例对象区初始化另一个对象的时候
  • 函数的参数是类的对象的时候(非引用)
  • 函数的返回值是函数体内局部对象的类的对象时,此时发生(Named return Value优化)NRV优化,但是由于返回方式是值传递,所以会在返回值的地方调用拷贝构造函数
    • 另:第三种情况在Linux g++ 下则不会发生拷贝构造函数,不仅如此即使返回局部对象的引用,依然不会发生拷贝构造函数

    • 在c++编译器发生NRV优化,如果是引用返回的形式则不会调用拷贝构造函数,如果是值传递的方式依然会发生拷贝构造函数。

六、拷贝构造函数如果用值传递会有什么影响?

如果把拷贝构造函数的参数设置为值传递,那么参数肯定就是本类的一个object,采用值传递,在形参和实参结合的时候,是需要调用本类的拷贝构造函数,就形成一个死循环,是为了避免拷贝构造函数无线递归下去

七、说一说了解的移动构造函数?

  • 有时候我们会遇到这样一种情况,我们用对象a初始化对象b后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a的空间呢?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷;

  • 拷贝构造函数中,对于指针,我们一定要采用深层复制,而移动构造函数中,对于指针,我们采用浅层复制;

  • C++引入了移动构造函数,专门处理这种,用a初始化b后,就将a析构的情况;

  • 与拷贝类似,移动也使用一个对象的值设置另一个对象的值。但是,又与拷贝不同的是,移动实现的是对象值真实的转移(源对象到目的对象):源对象将丢失其内容,其内容将被目的对象占有。移动操作的发生的时候,是当移动值的对象是未命名的对象的时候。这里未命名的对象就是那些临时变量,甚至都不会有名称。典型的未命名对象就是函数的返回值或者类型转换的对象。使用临时对象的值初始化另一个对象值,不会要求对对象的复制:因为临时对象不会有其它使用,因而,它的值可以被移动到目的对象。做到这些,就要使用移动构造函数和移动赋值:当使用一个临时变量对象进行构造初始化的时候,调用移动构造函数。类似的,使用未命名的变量的值赋给一个对象时,调用移动赋值操作

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leisure-pp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值