目录
一、为什么cout,cin可以自动识别类型?
我们知道cout是ostream类的对象,cin是istream类的对象,并且流插入运算符“<<”只能用于内置类型,不能用于自定义类型。
为什么可以用于自定义类型呐?
如下:
是因为C++进行了运算符重载,然后又通过函数重载,所以可以自动识别不同内置类型。
二、留提取运算符重载(<<)
想要自定义类型也可以用留提取运算符,此时需要自己定义留提取运算符重载。
void operator<<(iostream& out) { out << _year << "年" << _month << "月" << _day << "日"; }
但此时我们会发现,如下情况:
会发现p1在运算符左边,cout对象在右边。
原因在于:双操作数的运算符规定,第一个参数是左操作数,第二个参数是右操作数。而运算符重载函数的第一个形参被this指针隐式占用了,ostream类对象的引用在第二个形参位置,所以在调用运算符重载使,只能是this指针指向的对象在运算符的左边,cout对象在运算符的右边,但这又不符合留提取的含义。
为了解决这一问题,有如下方法:
将运算符重载创建为全局函数:
这样就不存在this指针占用的问题,可以将形参位置条调换,就可以像正常情况那样调用运算符重载。
接着又产生一个问题,运算符重载不在是类的成员函数,而大多数情况成员变量都会定义为私有或保护,这就导致,运算符重载不能使用成员变量,此时有如下解决方法:
(1)、创建getX,setX等等成员函数,间接使用成员变量;
(2)、将运算符重载设置为类的友元函数。
上述问题明白后,这里又有一个新的问题:
日常的运算符是支持链式调用的,所以我们还需要完成这个操作。
很显然,这是返回值的问题,我们返回cout对象的引用out就可以了;
ostream& operator<<(ostream& out,Date& d) { out << d._year << "年" << d._month << "月" << d._day << "日"; return out; }
三、留插入运算符重载(>>)
istream& operator>>(istream& in, Date& d) { cin >> d._year >> d._month >> d._day; return in; }
注意事项与cout类似。
四、对上述的总结:
(1)、其他运算符一般实现为成员函数,而=运算符必须实现为成员函数,<<、>>运算符必须实现为全局函数,这样才能让流对象作为第一个参数,才符合可读性;
(2)、流本质是为了解决自定义类型的输入和输出,这弥补了C语言的printf和scanf不能操作自定义类型的不足;
五、const成员
将 const 修饰的 “ 成员函数 ” 称之为 const 成员函数 , const 修饰类成员函数,实际修饰该成员函数 隐含的 this 指针 ,表明在该成员函数中 不能对类的任何成员进行修改。(const Date* this)。
看如下情况:我们发现当对象p1被修饰成const后就不能正常调用成员函数。原因在于p1被const修饰后,&p1为(const Date*)类型,而普通成员函数的this指针是(Date*)类型,这属于将权限放大问题,this指针就不能正常接收实参。此时我们规定如下:在成员函数的后面加一个const(若函数的声明和定义是分开的,就声明和定义后面都需要加const)就可以将this指针改为(const Date*)类型。再如下:一般的类对象可以调用const成员函数,这属于权限缩小,是可以被允许的。成员函数原则:
1.能定义成const的成员函数都应该定义成const,这样const对象和非const对象都可以调用。
2.要修改成员变量的成员函数,不能定义成const。(例如++运算符重载里面可能会改变成员变量day、month、year,而const成员函数的this指针是(const Date*)类型,看const位置就知道是解引用不能修改,也就是成员变量不能被修改。)。
3.注意<<、>>运算符重载后面不能用const修饰,因为在后面用const修饰的是*this,而这两个运算符重载不是成员函数,不存在this指针。
4.普通成员函数和const成员函数的this指针类型不同,所以是可以构成函数重载的。
六、默认成员函数-取地址操作符重载
实现如下:
Date* operator&() { return this; } const Date* operator&()const { return this; }
虽然看起来函数名一样,但参数类型不一样,因为下者后面被const修饰了,所以this指针是(const Date*)类型,而上者this指针是(Date*)类型,所以参数类型不一样,可以构成重载。
注意:该成员函数时默认采用函数,若没有显示定义,编译器会自动生成默认成员函数。所以平时&可以直接用。