自学内容网 自学内容网

初识C++·类和对象(中)(3)

前言,最难的已经结束了,来点轻松了放松一下。

目录

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;
}

重载&符号其实就是取地址,也就是取自定义类型的地址,但是实际上如果我们不显示调用编译器默认的函数也够用,那么为什么还要单独拎出来呢?
比如返回地址的时候,我想整蛊一下别人呢,比如我返回空,返回假地址,当然平时不用显式定义,默认生成的就够用了。


类和对象中就结束了,终于结束了,挺多的,

感谢阅读!


原文地址:https://blog.csdn.net/2301_79697943/article/details/138042030

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!