之前我们已经讲过了类和对象,但是其中我们没有仔细的分析构造函数以及拷贝构造函数。
现在我们仔细的来分析一下这两类函数。
**构造函数**
在写构造函数时,必要情况下我们要给一些值进行初始化,不然在运行时可能会出现无法预知的错误
初始化也分为两种:
(1)第一种是缺省的,也就是在定义构造函数时,我们就给其对象赋予初值,当在使用构造函数时,如果没有给其赋值,那么系统就会使用我们默认给的值
例如:
#include<iostream>
using namespace std;
class Time
{
public:
//需要注意,构造函数的名字与类名一定要一致
Time(int hour = 0,int minute = 0,int second = 0)
{
_hour = hour;
_minute = minute;
_second = second;
}
private :
int _hour;
int _minute;
int _second;
};
int main()
{
Time time1();//使用缺省值
Time time2(2017,10,22);//重新赋值
cout<<time1<<endl;
cout<<time2<<endl;
}
(2)第二种就是用初始化列表进行初始化,以上面的例子为继:
格式为:
Time(int hour = 0 , int minute = 0 ,int second = 0 )
:_hour(hour),_minute(minute),_second(second)
{}
这种情况就显得很简单了,初始化时都会进行。
接下来就是拷贝构造函数了,拷贝构造函数也是构造函数的一种,但是它提供参数,但没有返回值。
Time(const Time& t)
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;
}
拷贝时存在深拷贝和浅拷贝
//拷贝构造浅拷贝
String(String& s) :_str(NULL)
{
_str = s._str;
}
//深拷贝
String(String& s)
{
String tmp(s._str);
swap(_str, tmp._str);
}
为什么会存在深拷贝和浅拷贝??深拷贝与浅拷贝有哪些区别?
假如我们在学校里都不爱写作业,那么我们就会去抄作业,然后我们选了一个学习中等的同学的作业去抄,抄完了之后,那个同学发现他写错了,那他就会改正,那借他作业抄的同学也要跟着改正,这就相当于是浅拷贝。 如上,_str 和 s._str 指向的是同一块空间,在我们修改或更新 s._str 的时候,原本写好的 _str 就会跟着改变,这就是浅拷贝。而深拷贝就相当于是 A 把作业借给了 B,B 作业写完了之后借给了C,A 修改作业但是 C 不知道,C 就不会修改他的作业,除非有人告诉他。上面的例子就是:s._str 拷贝给了 tmp ,然后 tmp 把自己的值给了 _str ,这时 tmp 出了这个作用域就已经不存在了, _str 和 s._str 就互相不干扰了。实际上通俗的讲,就是 s._str 和 tmp 各指向了一块空间,地址不同,但是内容却相同,然后 _str 也指向了 tmp 的那块空间,当tmp不存在的时候,那块地址还有 _str 指向,所以不会销毁 。但是 s._str 和 _str 又没有指向同一块空间,所以 s. _str 改变不会改变_str的值。
下面几张图就是我们在深浅拷贝时观察到的,就会很容易的区分出深浅拷贝
浅拷贝前后的地址:
深拷贝前后的地址:
拷贝构造里还有几种情况值得我们注意:
(1)用类的一个对象去初始化另一个对象时需要调用拷贝构造函数
(2)当函数的返回值是类的对象或引用会调用拷贝构造函数
(3)当函数的形参是类的对象时,使用值传递的方法传递时会调用拷贝构造函数,如果是引用则不会调用
代码做证明:
#include<iostream>
using namespace std;
class AA
{
public :
//构造函数
AA(int a)
{
_a = a;
}
int get()
{
return _a;
}
//情况一 初始化一个对象
AA(AA& a)
{
_a = a._a;
cout << "该情况调用了拷贝构造函数!" << endl;
}
//情况二,返回值是对象类型
//为什么调用拷贝构造函数,因为函数体内生成的对象aa是临时的,离开这个函数就消失了。
//则会调用拷贝构造函数复制一份再传回。
AA get_A()
{
AA a(1);
return a;
}
//返回值为引用类型,返回的是别名,则不需要调用
AA& get_A1()
{
AA a(2);
return a;
}
//情况三,对象类型做参数时,值传递
int get_A2(AA a)
{
_a = a._a;
return _a;
}
//引用做参数时,传给的是别名,不需要拷贝
int get_A3(AA& a)
{
_a = a._a;
return _a;
}
private:
int _a;
};
void test()
{
//第一种情况
//AA x(3); //调用构造函数
//AA y(x); //调用拷贝构造函数
/*cout << x.get() << endl;
cout << y.get() << endl;*/
第二种情况
//AA x1(5);
//x1.get_A();//调用拷贝构造函数
//x1.get_A1();//不调用拷贝构造函数
//第三种情况
AA x2(4);
int c = x2.get_A2(x2);//调用拷贝构造函数
int d = x2.get_A3(x2);//不调用拷贝构造函数
}
#include"String.h"
#include<stdlib.h>
int main()
{
test();
system("pause");
return 0;
}
到这里,拷贝构造函数就告一段落,但是学习却没有停止,若有不足,希望大家能够多多指教。