前言,最难的已经结束了,来点轻松了放松一下。
目录
1 流重载
2 const成员
3 取地址及const取地址操作符重载
1 流重载
C语言中printf和scanf是有局限性,只能直接打印内置类型,对于自定义类型就哦豁了,所以在C++中就引用了流的概念,也就是cou cin:
为什么说打印输出的时候不需要占位符,这就是因为流就是一个重载了的函数,所以每次打印的时候都会调用对应的重载函数,比如多次打印的时候,printf一下就打印出来了,但是对于流不行,它要调用许多次重载函数,才能打印出,这也就导致了C++效率不如C语言高,对于不同类型,都可以进行打印,那么我们显式实现一下流重载:
首先我们要知道cout和cin来源于io流,作为一个全局对象出现的,所以cin的类型是istream,cout是ostream的,所以我们有一个参数的类型一定是ostream,传的参数是cout。
void Date::operator<<(ostream& out);//流重载
声明一下,我们先作为成员函数实现一下:
void Date::operator<<(ostream& out)//流重载
{out << _year << "年" << _month << "月" << _day << "日" << endl;
}
out是形参,用来接收cout,好了,我们实验一下:
cout << d1;d1.operator<<(cout);
试问哪种形式是正确的?
不墨迹了,第二种是正确的,这与参数的使用顺序有关系,因为是成员函数,所以有一个默认的this指针,但是cout传给了第一个参数,也就是this,d1传给了ostream,这是不是倒反天罡了?
所以:
这样,就拿捏了?
并没有,因为有悖于常态,我们正常使用都是流在前,参数在后,这反过来了还,所以呢,自己控制参数就可以防止反过来的情况:
void operator<<(ostream& out, const Date& d)//流重载
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}
重载为全局函数就ok了,就可以使用cout << d1打印,但是又有问题了,如果我们连续打印呢?
这个其实和连续赋值是一样的,所以我们只需要加上返回值:
ostream& operator<<(ostream& out, const Date& d)//流重载
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
返回引用是因为原来的运算符重载返回的就是引用,所以我们也返回引用就行。
但是因为我们重载成了全局的,所以要访问就必须把成员变量置为公有的,怎么解决呢?
我们可以使用友元的方法,这里简单提一下,下篇文章介绍:
即我们把这个函数置为友元函数,也就是你是我的朋友,那我就可以用你的东西了:
class Date
{friend ostream& operator<<(ostream& out, const Date& d);
public:
private:int _year;int _month;int _day;
};
在函数名前面加一个friend,你是我的朋友,私有的成员变量你也可以访问了。
cin输入也是一样的,就不做演示了。
2 const成员
先来看这样一段代码:
int main()
{const Date d1(2020, 1, 17);d1.Print();return 0;
}
当d1被const修饰,我们还能调用成员函数吗?这是不可以的,因为const修饰了d1,也就说明d1的权限是const,但是成员函数指针是Date* const this,如果调用函数,就会存在权限放大的问题。
那么祖师爷的解决方法是,散装const来解决:
class Date
{
public:void Print()const;
private:int _year;int _month;int _day;
};
void Date::Print()const
{cout << _year << '-' << _month << '-' << _day << endl;
}
即是函数的后面加一个const,很奇怪对吧,补丁缝缝补补,这个const修饰的是Date* this的*this,加了const参数就变成了const Date* const this,就不存在权限放大的问题,因为const修饰*this的时候,指针指向的元素就不能被修改,所以对于+ -等函数,不修改成员变量的,都可以用const修饰。
那么如果成员函数用了const修饰,但是d1没有被const修饰,调用函数的时候会不会报错呢?
实际上是不会的,因为权限缩小是没有问题的。
所以写函数的时候,只要不是修改成员变量我们把const往上一加是没有问题的。
3 取地址及const取地址操作符重载
这是最后一个成员函数了,是比较简单的,我们看一段代码:
class A
{
public:A* operator&(){cout << "A* operator&" << endl;return this;}const A* operator&()const{cout << "const A* operator&" << endl;return this;}
private:int _a = 1;int _b = 2;int _c = 3;
};
int main()
{A a1;const A aa1;cout << &a1 << endl;cout << &aa1 << endl;return 0;
}
重载&符号其实就是取地址,也就是取自定义类型的地址,但是实际上如果我们不显示调用编译器默认的函数也够用,那么为什么还要单独拎出来呢?
比如返回地址的时候,我想整蛊一下别人呢,比如我返回空,返回假地址,当然平时不用显式定义,默认生成的就够用了。
类和对象中就结束了,终于结束了,挺多的,
感谢阅读!