TIPS
构造函数 析构函数 拷贝构造函数 运算符重载 赋值运算符重载 当代码当中的运算符连接的全是内置类型的时候,由于内置类型,它是知道该怎么去进行运算的,所以说会直接转化为指令,然后但凡有一个不是内置类型,而是属于自定义类型,那么这时候就会转化为去调用一个函数,就是你自己写的运算符重载
接下来我还需要对运算符重载知识进行进一步补充:
一,关于运算符重载的++与–前置/后置的效率与其他补充
对于++与–的前置还是后置的问题,一般来讲的话,如果说对于内置类型而言,这前置与后置的效率相差并不是很大,可以说是微乎其微; 但是如果说对于那些自定义类型的前置++与后置++而言的话(减也是一样),前置的效率肯定是比后置要更高一点。 因为对于后置而言的话,你需要多拷贝两次,第一次拷贝就是因为由于你是后置,所以说你需要返回变化之前的值,所以说你需要在变化之前把原先那个直线给他拷贝一份作为最终的返回值;然后第二次的多余拷贝就在于在函数返回的时候,这时候不能采用引用返回,而是只能采用传值返回,这也就意味着有多需要去生成一个临时变量来存储这个返回值,而这些对于前置而言的话都是不存在的,所以说后置的效率会更慢一点 然后对于前置与后置再进行运算符重载的时候,区分的标志就在于参数,函数名称肯定都是一模一样的,都是operator符号,对于后置而言的话就在参数那边加一个int以示区分
d1++ ;
Date operator ++ ( int ) ;
++ d2;
Date operator ++ ( ) ;
二,关于运算符重载的传参顺序问题(全局函数+类成员函数)
操作数与函数参数从左往右必须一一对应(并不要求类型也一样)
任何一个操作符的话,他肯定都会有一个或者多个若干个操作数 ,这些操作数之间肯定有左右关系,谁在左边谁在右边之类的 不管这个运算符重载充当的是全局函数还是类当中的成员函数,这个运算符各个操作数的左右顺序就直接决定了在运算符重载函数当中各个参数的左右顺序,就是说操作数的左右顺序与参数的左右顺序必须是要一模一样与完全一一对应的,不然的话你这个运算符重载函数就会出问题,达不到想要的执行效果 当运算符重载充当全局函数的时候就问题不大,因为各个操作数的左右顺序与函数参数的左右顺序都是十分明确的,左右顺序之间是否一一对应上的话肉眼就能看出来 当运算符重载函数充当类的成员函数的时候,由于这边有个小坑,主要是这个this指针,this指针首先它是隐藏的,并且充当的是类当中成员函数的第一个参数,所以说类当中成员函数的第一个参数一定是那个隐藏掉的this指针,这点非常关键 这个this指针充当的是一个函数的形参,它对应的一个实参:就是实例化对象的地址,这两个成一对,他们都是在代码当中是隐藏的,也就是不能够显示出现,是看不见的。 所以如图:
三,关于指针传参的权限大小(有关于const修饰)问题
首先需要复习一下之前的那个知识,就是说如果说用const去修饰指针的话,这个const如果出现在星号的前面,那么就表示不能去修改这个指针所指向的内存空间里面的数据;如果说那个const出现在那个星号的右边的话,就表示不能修改这个指针本身,也就是说不能去修改这个指针所指向的地址,这指针所指向的那块内存空间里面的数据可以去改变。 然后this指针他其实也是被const给修饰的,只不过那个const应该出现在那个星号的右边: 类名 const this * 然后至于权限的理解,对权限大小的判断,这个与之前的引用都是完全一模一样的,这边的这个权限实际上就是指读写方面,读的话,权限相对来说就要小一点,写的话就说明权限很大。如果被const修饰了,那么就表示只读而不能写。 然后对于指针传参,从实参到形参的过程当中,权限只能够平移与缩小,而不能够进行权限的放大 ,比如说原先的实参指针是const A* ,在形参当中指针的类型变成了A*,那么这个相当于就是权限的放大,这个是不被允许的,权限只能够缩小与平移。这个指针传参的权限大小问题,尤其是在类的成员函数访问当中去指针传参的时候尤其需要注意。 很明显对于这个权限起决定性作用的就是是否被const修饰 ,但是仅局限于这个指针类型当中*的前面部分,后面部分有没有const与这边的权限问题,一点关系都没有。 以上三点就是补充
const修饰的成员函数
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针 ,表明在该成员函数中不能对类的任何成员进行修改。 所谓的const修饰的成员函数,其实在本质上就是去修饰这个this指针 ,因为按道理来说,原先这个this指针它的类型应该是类名* const this,正是因为如此,所以说是可以去修改this指针所指向的内存空间当中的内容。如果说我需要禁止修改,那就需要在函数定义的时候,在this指针的星号前面加上一个const,但是由于一个很恶心的地方就在于,This指针在形参那边是不能够进行显示出现,this倒是在成员函数里面是可以进行显示的使用 ,所以这就导致没有办法去修改它的一个默认指针类型。只能想出一个很挫的办法,就是说在成员函数定义的时候,在它的参数括号后面去加上const ,实际上就是去修饰这个this指针,把它的权限给他放小。
关于iostream,istream,ostream,cin,cout与流插入,流提取运算符重载的新认识
整体逻辑理一下是这样子的,首先就是在头文件当中去定义了两个类:分别是istream与ostream 然后对于这两个类istream,ostream又分别创建了各自的两个实例化对象cin与cout ,然后就是在对运算符流插入流提取进行重载,也就是说去实现(operator>> operator<<)的这么一个函数;在具体实现函数的逻辑的时候:又运用到了函数重载知识,也就是说函数名称是一样的,但是对于不同的内置类型单独设置了一个函数(参数不同,其实就是说构成了函数重载),所以这就导致你在用的时候有点能够自动识别类型的这种感觉,但是在底层看来的话,就是对不同的那些内置类型进行了各自的函数重载分别处理而已… 流插入流提取的运算符重载函数当中已经把内置类型全部实现完了,也就是说支持内置类型的一个输入与输出,但是如果说我创建了一个自定义类型的话,想用这些运算符进行输入输出的话,那我就继续像库当中一样再去运算符重载+函数重载一下下即可 <<操作符的话,它是有两个操作数,其中这个cout是类对象,是ostream的实例化对象,然后这个类ostream是库定义的 ,也就是说是在iostream这个头文件当中去定义的,所以说你只要把这个头文件给他包含上,再把命名空间给他展开,就可以去使用了。 代码演示:注意一下这边的函数的返回值,之所以需要这么去设置,是因为为了可以让运算符连续使用。
# include <iostream>
using namespace std;
class Stu
{
public :
int age = 0 ;
double score = 0 ;
} ;
istream& operator >> ( istream& in, Stu& s)
{
cin >> s. age >> s. score;
return in;
}
ostream& operator << ( ostream& out, Stu& s)
{
cout << "年龄为:" << s. age << " " << "成绩为:" << s. score << endl;
return out;
}
int main ( )
{
Stu s1;
Stu s2;
cin >> s1 >> s2;
cout << s1 << s2 << endl;
return 0 ;
}
类中友元函数的声明
对于一般的函数来说,如果说是在类外面的话,是无法对类的实例化对象进行访问到他的私有成员。但是如果硬要访问的话也不是不可以,就在那当中去声明一下,这个函数是我的朋友,是可以在类外面直接访问我的私有成员变量,没事儿。在类中就这样去声明友元函数
friend 友元函数的声明;
代码样本
# include <iostream>
using namespace std;
class Stu
{
private :
friend istream& operator >> ( istream& in, Stu& s) ;
friend ostream& operator << ( ostream& out, Stu& s) ;
int age = 0 ;
double score = 0 ;
} ;
istream& operator >> ( istream& in, Stu& s)
{
cin >> s. age >> s. score;
return in;
}
ostream& operator << ( ostream& out, Stu& s)
{
cout << "年龄为:" << s. age << " " << "成绩为:" << s. score << endl;
return out;
}
int main ( )
{
Stu s1;
Stu s2;
cin >> s1 >> s2;
cout << s1 << s2 << endl;
return 0 ;
}