赞
踩
目录
一般来说自定义类型是不支持运算符的,想支持的话就必须运算符重载
其中重载流插入的其中一个对象便是cout
cin和cout分别是istream和ostream类型的一个对象,它是在iostream那个头文件里定义的
这些都是C++已经写好在库里面的众多重载函数,所以说cout能支持内置类型
我们通常一开始会这样运算符重载<<
- void operator<<(ostream& out){
- out<<_year<<"年"<<_month<<"月"<<_day<<"日"<<endl;
- }
因为双操作运算符,第一个参数是左操作数,第二个参数是右操作数
结果便是报错
究其原因就是在Date类中,this指针已经悄悄的将第一个参数,即左参数给占用了
所以应该变为下述所讲
但是此种方式又不适合我们平常所用的,不符合可读性
将此重载函数放到全局的位置,让ostream对象放到第一个位置,第二个位置才是自定义类型
但这又会出现另一个问题,就是类外面不能访问私有成员,所以又会报错
改正的方法是:将private暂时屏蔽
但是这样私有成员变得将不再安全
所以此种解决方案是不合理的
介绍另一种方法之前,先介绍一个新的东西:友元函数
加了友元之后,便可在不是某类里面访问某类的私有成员
就相当于,声明了这个友元函数是这个类的好朋友,这个类相信它,允许它访问
第二种解决方案就是在类里面加上一个友元声明
friend void operator<<(ostream& out, const Date& d);
为了能够连续的输出自定义类型,即能做到cout<<d1<<d2<<endl;
所以应该将其的返回值变为 ostream!
- //类里
- friend ostream& operator<<(ostream& out, const Date& d);
-
- //类外
- ostream& operator<<(ostream& out,const Date& d) {
- out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
- return out;
- }
流提取的第二个参数便不能加const了,因为他要走到自定义类型里面去
- //类里
- friend istream& operator>>(istream& in, Date& d);
-
- //类外
- istream& operator>>(istream& in, Date& d) {
- in >> d._year >> d._month >> d._day;
- return in;
- }
流本质是为了解决,自定义类型输入和输出的问题,因为普通的printf,scanf是无法解决复杂的自定义类型输入和输出的问题的
*是可以重载的
在正常情况下,下述代码是没有任何问题的
- Date d1(2024,7,17);
- d1.print();
但当我们变成这样呢
- const Date d1(2024,7,17);
- d1.print();
出现了错误
我们把print()函数拿过来综合对比
- void print() {
- cout << _year << "-" << _month << "-" << _day << endl;
- }
-
- const Date d1(2024, 7, 16);
- d1.print();
但this指针是隐藏的,无法将它找出来加上const
在成员函数的后面加const,来弥补无法直接在Date* const this 的前头加const的缺点,且这是规定
- void print() const{
- cout << _year << "-" << _month << "-" << _day << endl;
- }
-
- const Date d1(2024, 7, 16);
- d1.print();
此时的this就相当于变为 const Date* const this
非const对象也能调用,属于权限缩小
在问题一修正的基础上
第一个编不过,第二个又能编过
与问题一样,不给权限放大就可以了,加const,一般不会修改成员就加一下const
所以有两个原则
例如,+=就不能加const
- Date& operator+=(int day) {
- if (day < 0) {
- *this -= (-day);
- return *this;
- }
-
- _day += day;
- while (_day > getMonthday(_year, _month)) {
- _day -= getMonthday(_year, _month);
- _month++;
-
- if (_month > 12) {
- _year++;
- _month = 1;
- }
- }
- return *this;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
取地址重载有两个,但也是默认成员函数,不写也没有什么过多问题
- Date* operator&() {
- return this;
- }
-
- const Date* operator&() const {
- return this;
- }
先来看看原本的构造函数
- Date(int year = 1900, int month = 1, int day = 1) {
- _year = year;
- _month = month;
- _day = day;
-
- if (_year < 1 || _month>13 || _month<1 ||
- _day>getMonthday(_year, _month)) {
- assert(false);
- }
- }
在CPP中还给了另外一种定义构造函数的方法
函数体无法初始化引用成员,const和自定义类型成员没有默认构造
初始化列表是每个成员定义的地方
以前的Date类的三个私有成员变量没有在初始化列表显示定义,但是其实它也是有定义的,只是C++内置类型默认给随机值,而自定义类型会去调用它的默认构造函数
有些自定义成员想要显示定义,即,用自己的数值初始化
如下代码
-
- class A {
- public:
- A(int a = 0)
- :_a(a)
- {
- cout << "我已完成A构造" << endl;
- }
- private:
- int _a;
- };
-
- namespace lhl {
- class Date {
- public:
- Date(int year, int month, int day)
- :_ref(year)
- , _n(1)
- , _aa(10)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year,_month,_day;
- A _aa;
- int& _ref;
- const int _n;
- };
- }
-
- int main() {
- lhl::Date d1(2024, 7, 17);
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
那么有了初始化列表,但是不能只用初始化列表,因为有些初始化或者检查工作,初始化列表也不能全部搞定
初始化列表初始的顺序,跟初始化列表的顺序无关,只跟声明的顺序有关
- namespace lhl2 {
- class A
- {
- public:
- A(int a)
- :_a1(a)
- , _a2(_a1)
- {}
-
- void Print() {
- cout << "a1的值是" << _a1 << endl;
- cout << "a2的值是" << _a2 << endl;
- }
- private:
- int _a2;
- int _a1;
- };
- }
-
- int main() {
- lhl2::A aa(1);
- aa.Print();
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
根据上述表达,可能我们会以为a1和a2的值都是1,1
但是结果并不是
显而易见,a1为1,a2为随机值
为什么呢?
前面说过:初始化列表初始的顺序,跟初始化列表的顺序无关,只跟声明的顺序有关
这里先声明了_a2,后来才声明了_a1
所以先声明_a2,因为_a2(_a1),此时的_a1还没有被赋值,只是一个随机值,所以_a2也会变成随机值
后来声明_a1,_a1(a),a为1,所以_a1为1.
以上便是本篇博文的学习内容,如有错误,还望各位大佬指点出来,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。