在C++中,牵扯到两个对象相互初始化,赋值,经常会调用拷贝构造函数和赋值操作符,许多新手也经常在此迷惑,究竟何时调用拷贝构造函数,何时调用赋值操作符呢?

在语法层面上来说,当你需要用一个已经存在的对象来初始化一个之前未曾存在的对象时候,会调用拷贝构造函数,当两个对象都已经存在,将两者用=操作符作为参数调用时候,会调用赋值操作符,可是两者究竟有什么本质区别呢?

首先需要明白构造函数的功能,以及背后究竟背着我们做了些什么工作。

大家在看完书的时候,肯定会得出一个结论,就是用来初始化一个对象,就是包括了分配内存及初始化成员变量的功能,这个的确有这么一个功能,然而这里得从两个方面来讨论对象的初始化,在栈上分配和从堆上分配。

1.从栈上分配

从栈上分配,定义一个类对象,构造函数究竟是怎么工作的,什么时候分配内存,什么时候初始化成员变量?其实从函数的工作原理上来讲,已经不存在分配内存这一说法,在这个函数被调用前,esp就会被调整,预留一段函数帧来供栈上变量使用,栈上变量的标识符也引用了特定的栈上内存,当函数结束时候,会恢复现场,调整esp,那么该段内存被释放,也就是自动变量自动释放的原理。由此我们可以得出,构造函数并不存在分配内存这一说法,不过也可以称之为供编译器调整函数帧的功能。假如在不存在虚函数的情况下,构造函数仅仅用于初始化成员变量,而当存在虚函数的情况下,那么构造函数的另一个重要的功能就是写入虚表。

当类中存在虚函数的情况下,每个类都会对应一个虚表,虚表依次存放着类中声明的虚函数,并由构造函数写入到对象所占内存的头部,这是为了更好的实现继承及父子强制转换和多继承的用途。所以无论是什么构造函数,拷贝构造也好,普通的也好,一个重要的功能就是写入虚表指针并执行剩下的初始化语句。当然,在类中不存在虚函数的情况下,行为和赋值操作符没有什么不同。

2.从堆上分配

从堆上分配的行为和栈上差不多,就是分配内存的一步由new操作符分配并负责调用构造函数,构造函数依据传入的this指针来进行剩下的工作。

所以在从实现来讲,拷贝构造函数和赋值操作符的最大一个区别就是拷贝构造函数会覆盖未初始化类内存区的虚表,而赋值操作符仅仅执行函数体内内容,不会覆盖虚表。

共 0 条回复
暂时没有人回复哦,赶紧抢沙发
发表新回复

作者

sryan
today is a good day