[C++] 自定义的类如何使用“cout“和“cin“?(含日期类实现)

news/2024/9/12 17:05:47/

一、引言

在C++中,“cin”和"cout"可以说是区别于C语言的一大亮点。

但是,它的自动识别类型,其本质不过是运算符重载。若真到了能够“自动识别”的那一天,人类大概也能进入新的纪元了罢。

对于我们自己写的类,想要用cout,cin,当然是可以的,我们只需自己写它的重载即可。

本文将以“cout”为例。

二、运算符重载

1、何为运算符重载 

运算符重载:

函数名: operator操作符
返回类型: 看操作符运算后返回值是什么
参数:操作符有几个操作数,它就有几个参数 

其中,有5 个符号是不能进行运算符重载的:::      sizeof         ?:      .      .* 

2、日期类

下面我们以日期类为例,熟悉运算符重载:

众所周知,如果直接在类中进行运算符重载,那么第一个操作数必定是隐含的this指针。

这样就会产生一个问题:本应是“cout<<d”,如今却要写成“d<<cout”

void Test3()
{Date d1(2023, 8, 9);Date d2(2023, 12, 20);Date d3(2003, 12, 1);d1 << cout;d2 << cout;d3 << cout;
}int main()
{Test3();return 0;
}

 

class Date
{friend void operator<< (ostream& out, const Date& d);public:// 获取某年某月的天数int GetMonthDay(int year, int month){int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){days[2] = 29;}return days[month];}// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;if (month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month)){cout << "非法日期" << endl;}}// 拷贝构造函数// d2(d1)Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}// 析构函数~Date(){;}//打印void Print() const{cout << _year << "年" << _month << "月" << _day << "日" << endl;}// 日期+=天数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;}// 日期+天数Date operator+(int day){Date tmp = *this;tmp += day;return tmp;}// 日期-天数Date operator-(int day){Date tmp = *this;tmp -= day;return tmp;}// 日期-=天数Date& operator-=(int day){if (day < 0){*this += (-day);return *this;}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;}// 前置++Date& operator++(){*this += 1;return *this;}// 后置++Date operator++(int){Date tmp = *this;*this += 1;return tmp;}// 后置--Date operator--(int){Date tmp = *this;*this -= 1;return tmp;}// 前置--Date& operator--(){*this -= 1;return *this;}// >运算符重载bool operator>(const Date& d){if (_year > d._year){return true;}else if(_year == d._year){if (_month > d._month){return true;}else if (_month == d._month){if (_day > d._day){return true;}}}return false;}// ==运算符重载bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}// >=运算符重载bool operator >= (const Date& d){return *this > d || *this == d;}// <运算符重载bool operator < (const Date& d){return !(*this >= d);}// <=运算符重载bool operator <= (const Date& d){return !(*this > d);}// !=运算符重载bool operator != (const Date& d){return !(*this == d);}// 日期-日期 返回天数int operator-(const Date& d){int num = 0;Date max = *this;Date min = d;int flag = 1;if (*this < d){flag = -1;max = d;min = *this;}while (max > min){num++;min++;}return flag * num;}void operator<< (ostream& cout) const{cout << _year << "年" << _month << "月" << _day << "日" << endl;}private:int _year;int _month;int _day;};

3、“cout<<d”

要想使得代码是“cout<<d”而非“d<<cout”,

其实也很简单。我们将<<的重载写在类的外面,就没有了“隐含的this指针”的限制。

但是这样又会产生一个问题:如何访问Date类的私有成员呢?

这时,我们可以利用“友元”来解决问题。

#include<iostream>
using namespace std;class Date
{
//设置友元friend void operator<< (ostream& out, const Date& d);public:// 获取某年某月的天数int GetMonthDay(int year, int month){int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){days[2] = 29;}return days[month];}// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;if (month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month)){cout << "非法日期" << endl;}}// 拷贝构造函数// d2(d1)Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}// 析构函数~Date(){;}//打印void Print() const{cout << _year << "年" << _month << "月" << _day << "日" << endl;}// 日期+=天数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;}// 日期+天数Date operator+(int day){Date tmp = *this;tmp += day;return tmp;}// 日期-天数Date operator-(int day){Date tmp = *this;tmp -= day;return tmp;}// 日期-=天数Date& operator-=(int day){if (day < 0){*this += (-day);return *this;}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;}// 前置++Date& operator++(){*this += 1;return *this;}// 后置++Date operator++(int){Date tmp = *this;*this += 1;return tmp;}// 后置--Date operator--(int){Date tmp = *this;*this -= 1;return tmp;}// 前置--Date& operator--(){*this -= 1;return *this;}// >运算符重载bool operator>(const Date& d){if (_year > d._year){return true;}else if(_year == d._year){if (_month > d._month){return true;}else if (_month == d._month){if (_day > d._day){return true;}}}return false;}// ==运算符重载bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}// >=运算符重载bool operator >= (const Date& d){return *this > d || *this == d;}// <运算符重载bool operator < (const Date& d){return !(*this >= d);}// <=运算符重载bool operator <= (const Date& d){return !(*this > d);}// !=运算符重载bool operator != (const Date& d){return !(*this == d);}// 日期-日期 返回天数int operator-(const Date& d){int num = 0;Date max = *this;Date min = d;int flag = 1;if (*this < d){flag = -1;max = d;min = *this;}while (max > min){num++;min++;}return flag * num;}private:int _year;int _month;int _day;};//运算符重载
void operator<< (ostream& cout, const Date& d)
{cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

效果 

void Test3()
{Date d1(2023, 8, 9);Date d2(2023, 12, 20);Date d3(2003, 12, 1);cout << d1;cout << d2;cout << d3;}int main()
{Test3();return 0;
}

 

如此,我们就实现了将自定义的类使用cout输出了。 


http://www.ppmy.cn/news/1020945.html

相关文章

[HDLBits] Mt2015 q4b

Circuit B can be described by the following simulation waveform: Implement this circuit. module top_module ( input x, input y, output z );//001 100 010 111assign z(xy); endmodule

AES加密(1):AES基础知识和计算过程

从产品代码的安全角度考虑&#xff0c;我们需要对代码、数据进行加密。加密的算法有很多种&#xff0c;基于速度考虑&#xff0c;我们一般使用对称加密算法&#xff0c;其中有一种常见的对称加密算法&#xff1a;AES(Advanced Encryption Standard)。在一些高端的MCU&#xff0…

集合工具类 Collections:提升集合操作效率

文章目录 多元素添加&#xff1a;addAll 方法随机置换&#xff1a;shuffle 方法自定义对象排序&#xff1a;sort 方法总结 在Java的集合框架中&#xff0c;Collections 是一个包含了许多操作集合的静态方法的工具类。通过使用 Collections 类提供的方法&#xff0c;我们能够更加…

MS9920T & MS9930T 3~10节锂电池或磷酸盐电池管理芯片 可分别替代BQ76920、BQ76930

MS9920T &#xff06; MS9930T 3~10节锂电池或磷酸盐电池管理芯片 可分别替代BQ76920、BQ76930 北京冠宇铭通 一级代理 可提供技术支持 产品简述 MS99x0T 系列模拟前端 (AFE) 芯片包含 2款&#xff0c;MS9920T 和 MS9930T 。其中 MS9920T 最 多支持 5 组电池串联&…

C++中的C风格字符串

C中的C风格字符串 C 风格字符串是一种特殊的字符数组。您在前面编写代码时使用过字符串字面量&#xff0c;它们就是 C 风 格字符串&#xff1a; std::cout << "Hello World";这与下面使用数组的方式等价&#xff1a; char sayHello[] {H, e, l, l, o, , W…

在SpringBoot项目中使用线程池创建一个线程案例

目录 1. 首先,在你的Spring Boot项目的配置类中,创建一个`ThreadPoolTaskExecutor`的Bean:2. 在你的Service类中,创建一个异步方法,并使用`@Async`注解将其标记为异步方法,该方法将在线程池中执行:3. 在Controller中调用异步方法:在Spring Boot项目中使用线程池可以通过…

Linux学习之sed删除、追加、插入、更改、读写文件、下一行、打印、退出和seq命令

cat /etc/redhat-release看到操作系统是CentOS Linux release 7.6.1810&#xff0c;uname -r看到内核版本是3.10.0-957.el7.x86_64&#xff0c;sed --version可以看到sed版本是4.2.2。 echo a : 1 : good : g >> sed_daicpnrwq.txt echo b : 2 : well : w >> sed…

如果新电脑是刚安装的mysql,但是旧电脑迁移过来的文件里面有相关的rails文件,运行rake db:migrate一直报错

$ bundle exec rake db:migrate#运行完命令报错 rake aborted! LoadError: libmysqlclient.so.21: cannot open shared object file: No such file or directory - /home/meiyi/.asdf/installs/ruby/2.6.9/lib/ruby/gems/2.6.0/gems/mysql2-0.5.5/lib/mysql2/mysql2.so /home/m…

ejbca:8443报文跟踪

安装客户端证书后&#xff0c;访问管理员页面 :8443/ejbca/adminweb 同时在wireshark抓包 1、客户端向对端发出Client hello 在Server Hello看到一个颁发给客户端的证书&#xff0c;颁发给5be85c9c1df9&#xff08;客户端node hostname 5be85c9c1df9&#xff09;但没有在Clie…

JAVA volatile 关键字

volatile 是JAVA虚拟机提供的轻量级的同步机制&#xff0c;有三大特性 1、保证可见性 2、不保证原子性 3、禁止指令重排 JMM JAVA内存模型本身是一种抽象的概念并不真实存在 它描述的是一组规则或规范&#xff0c;提供这组规范定义了程序中各个变量&#xff08;包括实例变…

指针---进阶篇(二)

指针---进阶篇&#xff08;二&#xff09; 前言一、函数指针1.抛砖引玉2.如何判断函数指针&#xff1f;&#xff08;方法总结&#xff09; 二、函数指针数组1.什么是函数指针数组&#xff1f;2.讲解函数指针数组3.模拟计算器&#xff1a;讲解函数指针数组 三、指向函数指针数组…

二、Linux中权限、shell命令及运行原理

shell命令及运行原理 我们使用Linux时&#xff0c;并不是直接访问操作系统&#xff0c;为什么不是直接访问操作系统呢&#xff1f; 如果用户直接访问操作系统&#xff0c;不仅使用难度大&#xff0c;而且不安全&#xff0c;容易把系统文件损坏。 那么我们通常是如何访问操作系统…

【Linux】云服务器自动化部署VuePress博客(Jenkins)

前言 博主此前是将博客部署在 Github Pages&#xff08;基于 Github Action&#xff09;和 Vercel 上的&#xff0c;但是这两种部署方式对于国内用户很不友好&#xff0c;访问速度堪忧。因此将博客迁移到自己的云服务器上&#xff0c;并且基于 Jenkins&#xff08;一款开源持续…

线上影院售票系统票商端H5小程序源码搭建

搭建一个线上影院售票系统票商端H5小程序源码是一个相对复杂的过程&#xff0c;需要涉及到前端开发、后端开发以及数据库的搭建等多个方面。具体步骤如下&#xff1a; 1. 确定需求&#xff1a;首先需要明确影院售票系统的功能需求&#xff0c;包括电影信息的展示、影院排片管理…

atx2环境搭建

1. 安装python3.9.16版本 Index of /ftp/python/3.9.16/ 在执行该命令前&#xff0c;建议先清理下brew的缓存 brew cleanup 如遇Python环境报错 Run Configuration Error: Please specify a script name 参考&#xff1a;https://blog.csdn.net/weixin_43919570/article/d…

SpringBoot复习:(23)ImportSelector的用法

功能&#xff1a; 定一一个字符串数组&#xff0c;每个元素都是一个类的全限定名&#xff08;包名类名&#xff09;&#xff0c;把这些类的实例注册到Spring 容器。 一、定义要注册的类&#xff1a; package cn.edu.tju.service;import org.springframework.context.annotatio…

【SpringBoot】日志是什么+基于lombok的日志输出

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE进阶 在我们日常的程序开发中&#xff0c;日志是程序的重要组成部分&#xff0c;想象⼀下&#xff0c;如果程序报错了&#xff0c;不让你打开控制台看⽇志&#xff0c;那么你能找到报错的原因吗…

LeetCode209. 长度最小的子数组

题目&#xff1a;LeetCode209. 长度最小的子数组 描述&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子…

计算机网络实验4:HTTP、DNS协议分析

文章目录 1. 主要教学内容2. HTTP协议3. HTTP分析实验【实验目的】【实验原理】【实验内容】【实验思考】 4. HTTP分析实验可能遇到的问题4.1 捕捉不到http报文4.2 百度是使用HTTPS协议进行传输4.3 Wireshark获得数据太多如何筛选4.4 http报文字段含义不清楚General&#xff08…

小程序自动化测试的示例代码

目录 背景 自动化 SDK 还原用户行为 总结 背景 上述描述看似简单&#xff0c;但是中间还是有些难点的&#xff0c;第一个难点就是如何在业务人员操作小程序的时候记录操作路径&#xff0c;第二个难点就是如何将记录的操作路径进行还原。 自动化 SDK 如何将操作路径还原这…