前言
不同于C语言其实是汇编语言的高级版本,c++有着自己的语言特性,就如同Java、Python一样,这些特性的实现细节由编译器实现,并对使用者透明。而C++中最常用到的思想就是对象思想,把任何事物抽象成一个对象,对象由两个维度组成:数据
和操作
(数据
就是C语言中的结构体),而操作中又有一部分是必须的,这也是编译器为我们提供默认函数的原因。C++和C另外一个重要的不同在于C++中规定编译器对于一些函数的隐式调用,如在初始化对象时对构造函数的隐式调用,对象赋值时对赋值运算符的隐式调用,这样规定的好处是代码编写量更小,但是也对使用者对C++标准的了解程度提出了更高的要求。
在C++中,每个类有以下几种默认的函数:
- 默认构造函数;
- 默认拷贝构造函数;
- 默认析构函数;
- 默认重载赋值运算符函数;
- 默认重载取址运算符函数;
- 默认重载取址运算符const函数;
- 默认移动构造函数(C++11);
- 默认重载移动赋值操作符函数(C++11)。
以对象为返回值的函数
我们先来看两个函数
int f1(){
int Tmp;
....
return Tmp;
}
A f2(){//f2是一个类
A Tmp;
....
}
return Tmp;
int main(){
int a=f1();
A b=f2();
}
让我们思考一下这两个函数有什么区别?区别在于返回值的数据类型不同,f1
的返回值是一个基本类型,而f2
的返回值是一个复合类型。我们知道,在c++中,一个类似于这样的语句T xx=function()
,编译器的处理步骤一般为:
- 调用function;
- 将function的
结果
通过mov等汇编指令赋值为xx变量所在的内存单元;
我们更仔细的来想一下第二步中的结果的存储位置:在执行到第二步时,我们已经从函数返回了,对于函数中的局部变量已经不能进行访问,那么我们的结果
究竟保存在哪里呢?对于诸如返回类型为char等基本数据类型的函数来说,可以通过寄存器(通常是eax
寄存器)。进行传值而对于结构体、对象等复杂数据结构来说,无法通过寄存器保存。一种妥协的方法是通过某种方式(在 MSVC下是调用者的栈空间)开辟一段内存,并将结果
从局部变量拷贝到该段内存中,注意:这段内存是无名字的,所以也叫将亡值
。
总结一下,假设函数流程如下:
A f2(){//f2是一个类
A Tmp;
....
return Tmp;
}
return Tmp;
int main(){
A b;
b=f2();
}
f2函数的在MSVC中的流程如下:
1.调用者(main函数)将将亡值的空间地址传入f2;(这一步对开发人员不可见)
2. f2做该做的事情;
3. f2调用A的拷贝构造函数将临时对象拷贝到将亡值空间中;
4. main函数调用赋值运算符函数完成该语句;
5. main函数调用将亡值的析构函数负责收尾;
另外对于语句A b=f2();
需要做一点特殊的说明,该语句实际上被转化为A b(f2())
,同时该语句的执行流程和上述一致,但是第四步和第五步不需要做。