赋值运算符/拷贝构造/构造/析构函数

赋值运算符

1, 禁止一个类对象指定给另一个类对象的方法:copy 赋值运算符声明为private,并且不提供定义。

2, 一个class对于默认的copy 赋值运算符,以下情况不会表现出位拷贝语意

1】 类内含成员对象,其类有一个copy 赋值运算符;

2】 类内基类有一个copy 赋值运算符;

3】  类声明了任何虚函数

4】  类继承自一个虚基类

注:上述4种情况类似拷贝构造,构造函数。

例子:编译器合成的copy 赋值运算内部调用基类/成员对象的copy 赋值运算

     

  

建议:尽可能避免虚基类的拷贝操作(因为虚基类会有多份拷贝实体),甚至,不要在虚基类中声明数据。

————————————————————————————————————————————————————————————————-

析构函数

什么时候合成?

1, class没有定义析构函数

2, 只有在class内带的member object(或class自己的基类)拥有析构函数时,编译器才合成。

否则,析构函数被认为不需要,就不需合成(更不需要被调用)

例子:不会合成(即使有虚函数)

      

    

   

注意:只有类中的基类或数据成员不含析构函数,该类就不会合成一个析构函数

      即使类中有虚函数,或继承自虚基类

一个class的析构函数被扩展的方式如下:

1,本身的destructor

2,如果class有member class objects,后者有destructors,那么它们以其声明顺序的相反顺序被调用;

1, 如果object内有vptr,则被重新设定,指向适当的base class的virtual table;

如果有任何非虚基类有析构函数,它们以其声明顺序的相反顺序被调用;

2, 如果有nonvirtual base class拥有destructor,而当前讨论的这个class 是最尾端的class,那么它们以其原来的构造顺序的相反顺序被调用。

注意:析构函数和构造函数的调用次序相反

一个最底层对象归还起内存空间前,依次变成各个基类(和析构函数的顺序有关)。

——————————————————————————————————————————————————————————

构造函数

默认构造函数什么时候合成?

即编译器需要时:

1>     带有默认构造函数的成员对象

2>    带有默认构造函数的基类

3>    带有虚函数的类,默认构造函数作用:此时,设置vptr

4>    带有虚基类的类,安排虚基类在每一个派生类对象的位置,用于执行期

注意:合成的构造函数,仅仅满足编译器的需要

最好使用成员初始化列表的情况:

1,初始化一个reference member;

2,当初始化一个const member时;

3,调用一个base class 的constructor,而它拥有一组参数时;

4,调用一个member class 的constructor,而它拥有一组参数时;

在这4种情况下,不使用成员初始化列表可以执行,但效率不彰,例如:

class word{

string name;

int cnt;

public:

word()

{

name=0;//编译器内部会产生临时对象string,最后再摧毁临时对象

cnt=0;

}

};

较佳的写法:

word::word:name(0)

{

cnt=0;

}

或者坚持此写代码风格:

word::word:cnt(0),name(0) //name的初始化早于cnt,因为其声明早于cnt

{

 

}

 

注意:list中的项目次序由class中的members声明次序决定,不是由initialization list中的排列次序决定。

例子:

   

  

有陷阱的写法:i的值不确定

修改后的写法:ji之前被赋值

————————————————————————————————————————————————————————————

拷贝构造函数

被调用的3种情况?

1》  赋值

class X{};

X x;

X xx=x;

2》参数

3》返回值

1,当编译器不合成默认拷贝构造函数时,使用位逐次拷贝。

什么时候类不表现出位逐次拷贝?

1,类内含成员对象,其类有一个copyconstructor (无论是编译器合成还是编写的)

2,类内基类有一个copy constructor(无论是编译器合成还是编写的)

3,类声明了任何virtual function

4,类派生自一个继承链,其中有virtual base class

前2种情况:编译器将member/baseclass的copy constructors 安插到被合成的copy constructor

注:以上四个条件类似默认构造函数的合成!!!!!!!!!!!!

第三种情况---内含虚函数的情况:重新设置虚表指针

重新设置虚表指针-例子

    

  

    

    

第四中情况----虚基类子对象:让派生类对象中的虚基类子对象位置准备妥当

         在编译器合成的copy constructor 中插入一些代码,设定 virtualbase class pointer/offset的初值。

针对拷贝构造函数的优化

   

使用者的优化:优化后:直接返回对象,去除临时对象

     

编译器的进一步优化,去除临时对象:

   

   

拷贝构造函数的问题:

拷贝构造函数中使用memcpy()时,如果类函数vptr,那么vptr会被清零。

例子1:效率更高

     

例子2:但当类函数虚函数或虚基类时,上述函数会导致虚指针被改写:memsetvptr清零

   


  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

多则惑少则明

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

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

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

打赏作者

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

抵扣说明:

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

余额充值