拷贝构造函数
拷贝构造函数是一种特殊的成员函数
一.特征:
1.拷贝构造函数时构造函数的一种重载形式。
2.拷贝构造函数的参数只有一个且必须使用引用参数,使用传值方式会引发无穷递归调用。
拷贝构造函数的使用语句如下:
上面的语句就会将d1中的内置成员变量拷贝到对象d2中,但是此时拷贝是浅拷贝,只是将两个指针指向同一块空间。
上面那种传参方式是错误的,因为本来传参方式中的传值操作就是一种拷贝构造,这样会造成无穷的递归,所以在创建拷贝构造函数的时候要进行引用传参如下图:
拷贝构造函数属于默认成员函数,和构造函数和析构函数一样,我们不写编译器会自动生成一个拷贝函数,而这个拷贝构造是对内置类型的一种浅拷贝或者叫做值拷贝。而浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。对上面这样的内置变量是可以进行拷贝的,但是对一些内置函数是不能进行拷贝的如下图:
上面这段如果用编译器默认的拷贝构造函数就会报错,因为这时两个对象中的_a指针指向的是一块空间,所以在调用析构函数的时候会对这块空间调用两次析构函数,此时这两个对象中的一个插入删除这块空间都会对另一个对象造成影响,所以默认生成的拷贝函数来说是不能拷贝指针这种要开空间的成员变量的。
运算符重载与友元函数
一.运算符重载
C++为了增加代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数。
运算符重载的具体语句如下:
上面的代码是重载赋值运算符函数,其中operator表示运算符,因为会用到连续赋值运算,例如当i = j = k的时候,是右结合也就是先算j = k之后表达式返回值为j,然后让i = j自定义类型同理 d1 = d2 = d3先返回值d2之后d1 = d2,所以进行运算符重载的时候要有返回值。
对于上面的语句可以将返回值类型改为Date&,因为此函数的返回值出了函数后还存在所以可以改变返回值类型,此时改完之后就不会对返回值进行调用拷贝函数,可以提高效率。所以在函数传参的时候,自定义类型的对象,一般推荐用引用传参,如果使用传值传参也可以,但是每次都需要进行拷贝构造,会比引用传参慢。
二.运算符重载需要的注意:
注意:
1.不呢个通过链接其他符号来创建操作符,就是不能用c++中没有的操作符进行重载。
2.重载操作符必须有一个类类型或者枚举类型的操作数。
3.用于内置类型的操作符,其含义不能改变,例如内置的整形不能改变其含义。
4.做为类成员的重载函数时,其形参看起来比操作输数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参。
5.(:: , sizeof , ?: , . , .*)这五个括号中的运算符是不能重载的。
在对赋值运算符进行重载之后,就可以对自定义类型进行赋值语句如下图:
在上面的第128行的语句,此语句是属于拷贝构造函数而不是赋值重载语句。因为作为拷贝构造函数的时候,是将一个已经创建的对象,对一个还未创建的对象进行初始化,而赋值重载是对两个都已经创建的对象进行互相赋值。
三.const修饰成员变量与成员函数
const是用来保护对象的,const可以降低对象的权限,从而保护对象不被修改。
例如:
上面是用const修饰指针来控制指针指向的内容或者指针本身不被修改
有的时候我们不想我们定义的运算符重载函数中被编译器隐藏的this指针被修改,则我们首先可以将当前运算符重载函数放到全局变量中,但是这个时候就不可以使用类的内置成员变量了,所以此时如上面的代码,将const写在函数体的后面,这个时候就可以将隐藏的this指针进行const修饰,来保证this指针不给修改。
四.输入输出运算符重载
在C++中cout是属于ostream类,cin是属于istream类。
1.输出运算符重载:
此时输出运算符重载和正常重载不一样,如果将该重载函数放到类中,则编译器会自动在out参数前面放置一个this指针,如:
但是如果是这种情况,当调用该运算符函数的时候就要使用语句
这种不符合运算符重载要给用户带来方便的约定,所以此时就不能将重载函数写在类中,要将函数写在全局中,那么写在全局中怎么使用内置成员变量呢,那么这个时候就要用到友元函数了。
五.友元函数
当利用上面的语句无法实现的化就可以使用友元函数,友元函数的作用就是可以让函数在类外面也可以调用内置成员变量,所以此时在类中声明友元函数语句如下图:
而声明了友元函数之后就可以在类外使用成员变量了,所以输入输出的运算符重载函数语句如下图:
运算符重载应用->日期表的创建
具体代码如下:
头文件(.h文件)
在.h的头文件中将所有要重载的运算符函数进行声明,并定义一个日期类。
.cpp文件
上面的代码将所有的运算符重载的函数进行实现。
主函数(.cpp函数)
来测试这些运算符重载的函数运行是否正常。