类和对象(3)

具体如何重载需要引入一个概念。已知:内置类型可以直接使用运算符,cout会自动识别内置类型。cout如何自动识别类型的?cout和cin具体又是什么?
摘要由CSDN通过智能技术生成
接着日期类
void testDate6()
{
    Date d1;
    cin >> d1; //>>是流提取,意为从流中提取,放到d1中。
    cout << d1; //<<是流插入,意为把对象插入到流中。
}
这两个运算符都是需要重载的。
具体如何重载需要引入一个概念。
已知:内置类型可以直接使用运算符,cout会自动识别内置类型。
cout如何自动识别类型的?cout和cin具体又是什么?
先从下面这张图开始说明
cin和cout其实是全局的对象,包含在头文件iostream中
cin是istream类型的对象,cout是ostream类型的对象,ostream类型的对象还有cerr,clog。istream和ostream是流的类型
cout能输出各种类型就是因为cout把各种类型都重载了
cin >> a;
cout << a;
变量a通过运算符重载找到对应的重载函数,返回一个ostream类型,由cout << a;可知,打印是通过cout对象实现的,所以写日期类<<运算符的重载需要ostream类型的变量;>>运算符的重载需要istream类型的变量。
void operator<<(std :: ostream& out) //ostream在std中,没有展开std的话要声明所在域
{
    out << _year << "-" << _mouth << "-" << _day << endl;
}
不过这样写cout << d1;会报错。因为位置不对。
因为cout << a;在调用是会转换成cout.operator<<(a);而cout << d1;会转换成cout.operator<<(d1);d1和out类型不一致,没有找到匹配的重载函数,报错。想要调用应该是d1.operator<<(cout);运算符<<重载是写在日期类中的,应该是日期类来调用。
不写成重载形式的调用方式是d1 << cout;
之前规定过,当一个运算符是双操作数时,第一个数是左操作数,第二个数是右操作数。但是流插入运算符的语法是日期类插入到流中去,重载变成了流插入到日期类对象中。
函数调用只能像d1<<cout;这样调用的主要原因就是写成了日期类的成员函数。成员函数有一个规定死的:第一个参数必是隐含的this。
所以函数应该写在全局变量域中
void operator<<(std :: ostream& out, const Date& d)
{
    out << d._year << "-" << d._mouth << "-" << d._day << endl;
}
现在的问题就是_year这些成员变量是私有的。解决方案有两个。
1.写GetYear函数,GetYear函数如果是引用返回,引用接收,就和公开成员变量没什么区别了,可以对私有成员进行修改。
2.友元
class Date
{
    friend void operator<<(std :: ostream& out, const Date& d);
     //友元就是在前面加一个friend声明,同时声明operator<<函数
pubilc:
……
}
友元函数可以访问类的私有成员变量。
这里还有一个隐含的问题,class Date是定义在Date.h 中的,所以void operator<<(std :: ostream& out, const Date& d)函数往往会顺手写在Date.h中,而void operator<<(std :: ostream& out, const Date& d)又是全局变量函数,在test.cpp和Date.cpp中都有Date.h的展开,也就是说void operator<<(std :: ostream& out, const Date& d)函数被定义了两次,在符号表中存在两个相同的函数标识符,会报重定义的错。
类中的函数和全局变量函数都在静态区,为什么类中的函数不报错?
类中的函数默认是内联函数,不会放入符号表。即使类中定义的函数很长,不具备内联函数的条件,编译器不会展开这个函数,但是这个函数依然有内联函数的属性。声明了是内联后,编译器决定要不要展开。不展开也还是具备内联的属性。
问题解决了,但是和<<操作符的实际作用还存在区别,因为不支持连续流插入。
<<操作符是从左到右结合,cout << d1 << d2;先走cout << d1,再根据cout << d1的返回值执行 << d2。
class Date
{
    friend std :: ostream& operator<<(std :: ostream& out, const Date& d);
pubilc:
……
}
std :: ostream& operator<<(std :: ostream& out, const Date& d)
{
    out << d._year << "-" << d._mouth << "-" << d._day << endl;
    return out;
}
这样是为了连续的流插入。
流提取:
class Date
{
    friend std :: ostream& operator<<(std :: ostream& out, const Date& d);
    friend std :: istream& operator>>(std :: istream& in, Date& d);
pubilc:
……
}
std :: ostream& operator<<(std :: ostream& out, const Date& d)
{
    out << d._year << "-" << d._mouth << "-" << d._day << endl;
    return out;
}
std :: istream& operator>>(std :: istream& in, Date& d)
{
    in >> d._year >> d._mouth >> d._day; //这里输入非法日期是不会报错的,所以应该再加上一个检查
    return in;
}
流本质上是一个类型(istream/ostream)的对象,这个对象的作用是输入/输出。在这个对象中的数据都会输出到屏幕上/存储进内存中的变量里。是由系统控制的。
到这里,日期类才算有一个完整的框架&
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值