C++类的默认成员函数——赋值重载-创新互联
一、概念
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类 型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
1、 不能通过连接其他符号来创建新的操作符:比如operator@
2、 重载操作符必须有一个类类型参数用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
3、 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
4、 .* :: sizeof ?: .
注意以上5个运算符不能重。
二、赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值
返回*this :要复合连续赋值的含义
三、
赋值运算符只能重载成类的成员函数不能重载成全局函数
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
四、
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
下面写一个完整的日期类来实现赋值运算符的重载:
Date.h 文件
文章名称:C++类的默认成员函数——赋值重载-创新互联
URL标题:http://pwwzsj.com/article/dhcjjj.html
#pragma once
#include
#includeusing namespace std;
class Date
{
// 友元函数 ==>这个函数内部可以使用 Date 对象访问私有保护成员
//friend void operator<<(ostream& out, const Date& d); // 只能输出一个 cout<< d1 不支持连续输出 cout<< d1<< d2;
friend ostream& operator<<(ostream& out, const Date& d); // 只能输出一个 cout<< d1 不支持连续输出 cout<< d1<< d2;
friend istream& operator>>(istream& out, Date& d);
public:
// 构造函数频繁调用,所以直接放在类里面定义作为 inline
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
Print();
cout<< "初始日期错误"<< endl;
}
}
bool operator == (const Date& d) const;
bool operator >(const Date& d) const;
bool operator< (const Date& d) const;
bool operator >= (const Date& d) const;
bool operator<= (const Date& d) const;
bool operator != (const Date& d) const;
int GetMonthDay(int year, int month)
{
// 加 static 为了防止多次频繁调用函数之后多次频繁创建数组,加 static 数组在静态区上创建 每次访问都是这一个
static int Month_Day[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 2
&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
else
{
return Month_Day[month];
}
}
// 检查最开始就把日期写错
bool CheckDate()
{
if (_year >= 1
&& _month >= 1 && _month<= 12
&& _day >= 1 && _day<= GetMonthDay(_year, _month))
{
return true;
}
else
{
return false;
}
}
//void Print();
void Print() const;
// d1 + day
Date operator + (int day) const;
Date& operator += (int day);
// d1++ 后置++,返回++之后的
// ++d1 前置++,返回++之前的
// 直接按特性重载,无法区分
// 特殊处理,使用重载区分 后置 ++ 重载增加一个 int 参数跟前置构成函数重载进行区分
// Date operator++(); // 这样的话没办法区分写的是前置还是后置
Date& operator++(); // 前置
Date operator++(int); // 后置 加不加形参接收不接收都可以 但是规定类型是 int
// d1 - day
Date operator - (int day) const;
Date& operator -= (int day);
Date& operator--();
Date operator--(int);
// d2 - d1 ==>日期 - 日期 = 天数
int operator - (Date& d) const;
// 输出流<< 操作符<==>操作符可以接收内置类型的 无法接受自定义类型
// void operator<<(ostream& out); // 默认第一个参数是 this (放这里不太合适)
private:
int _year;
int _month;
int _day;
};
// 流插入重载
//
// void operator<<(ostream& out, const Date& d); // 放在类外面 将参数的位置可以改变
// 会被频繁调用 输出多行 应该加上 inline
// ostream& operator<<(ostream& out, const Date& d); // 放在类外面 将参数的位置可以改变
// 加上 inline 又链接不上,内联 不进 符号表 链接找不到 ===>所以 定义 和 声明 不要分离
inline ostream& operator<<(ostream& out, const Date& d)
{
// 因为函数在类外面定义的 所以无法访问 private 的成员
// 解决办法 1. 用 get_year get_month get_day 2. 把 private 的成员放开 public (不建议) 3. 友元函数
out<< d._year<< "-"<< d._month<< "-"<< d._day<< endl;
return out;
}
// 流提取重载
inline istream& operator>>(istream& in, Date& d)
{
in >>d._year >>d._month >>d._day;
assert(d.CheckDate());
return in;
}
Date.cpp 文件
在葫芦岛等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站设计、成都做网站 网站设计制作按需定制开发,公司网站建设,企业网站建设,成都品牌网站建设,全网营销推广,成都外贸网站制作,葫芦岛网站建设费用合理。#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
// 任何一个类要重载运算符只需要写一个 >和== 或者<和== 重载, 剩下比较运算符复用即可
// d1 == d2
bool Date::operator == (const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
// d1 >d2
bool Date::operator >(const Date& d) const
{
if ((_year >d._year)
|| (_year == d._year && _month >d._month)
|| (_year == d._year && _month == d._month && _day >d._day))
{
return true;
}
else
{
return false;
}
}
// d1< d2
bool Date::operator< (const Date& d) const// Date* const this, const Date
{
return !(*this >= d);
}
// d1 >= d2
bool Date::operator >= (const Date& d) const
{
return (*this >d) || (*this == d);
}
// d1<= d2
bool Date::operator<= (const Date& d) const
{
return !(*this >d);
}
// d1 != d2
bool Date::operator != (const Date& d) const
{
return !(*this == d); // 逻辑取反
}
// 先写 += 再复用到 + (调用两次拷贝)
// d1 + day
Date Date::operator + (int day) const // 不加引用;因为 ret 出了 Date 作用域就销毁了
{
Date ret(*this); // 拷贝构造
ret += day;
return ret; // 返回 ret 然后会拷贝构造
}
// d1 += day
Date& Date::operator += (int day)
{
if (day< 0)
{
return *this -= -day;
}
_day += day;
while (_day >GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
return *this;
}
// 如果先写 + 再复用到 += (会调用多次拷贝效率低)
//Date Date::operator + (int day) // 不加引用;因为 ret 出了 Date 作用域就销毁了
//{
// Date ret(*this); // 拷贝构造
//
// ret._day += day;
// while (ret._day >GetMonthDay(ret._year, ret._month))
// {
// ret._day -= GetMonthDay(ret._year, ret._month);
// ret._month++;
// if (ret._month == 13)
// {
// ret._year++;
// ret._month = 1;
// }
// }
//
// return ret; // 返回 ret 然后会拷贝构造
//}
//
d1 += day
//Date& Date::operator += (int day)
//{
// *this = *this + day;
//
// return *this;
//}
Date& Date::operator++() // 前置
{
//*this += 1;
//return *this;
return *this += 1; // 返回值没有销毁 用引用返回
}
Date Date::operator++(int) // 后置
{
Date temp(*this);
*this += 1;
return temp;
}
Date Date::operator-(int day) const
{
Date temp(
*this);
temp -= day;
return temp;
}
Date& Date::operator-=(int day)
{
if (day< 0)
{
return *this += -day;
}
_day -= day;
while (_day<= 0)
{
--_month;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date& Date::operator--()
{
return *this -= 1;
}
Date Date::operator--(int)
{
Date temp(*this);
*this -= 1;
return temp;
}
// d2 - d1 ==>日期 - 日期 = 天数
int Date::operator - (Date& d) const
{
int flag = 1;
Date max = *this;
Date min = d;
if (max< min)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
min++;
n++;
}
return n * flag;
}
流操作符<<
//void Date::operator<<(ostream& out) // 写在类里面的
//{
// out<< _year<< "-"<< _month<< "-"<< _day<< endl;
//}
//void operator<<(ostream& out, const Date& d) // 放在类外面 将参数的位置可以改变
//ostream& operator<<(ostream& out, const Date& d)
//{
// // 因为函数在类外面定义的 所以无法访问 private 的成员
// // 解决办法 1. 用 get_year get_month get_day 2. 把 private 的成员放开 public (不建议) 3. 友元函数
// out<< d._year<< "-"<< d._month<< "-"<< d._day<< endl;
// return out;
//}
//void Date::Print() // const Date* const this
void Date::Print() const // const Date*
{
cout<< _year<< "-"<< _month<< "-"<< _day<< endl;
}
TestDate.cpp 文件
//void TestDate1()
//{
// Date d1(2022, 11, 8);
//
// (d1 + 4).Print(); // 跨天
// (d1 + 40).Print(); // 跨月
// (d1 + 400).Print(); // 跨年
// (d1 + 4000).Print();// 跨闰年
//
// Date ret1 = ++d1; // d1.operator++(&d1)
// Date ret2 = d1++; // d1.operator++(&d1, 0) 整数传什么都可以 只是为了构成重载进行区分
//}
void TestDate2()
{
Date d1(2022, 11, 14);
//(d1 - 4).Print(); // 跨天
//(d1 - 40).Print(); // 跨月
//(d1 - 400).Print(); // 跨年
//(d1 - 4000).Print();// 跨闰年
//Date ret1 = ++d1; // d1.operator++(&d1)
//Date ret2 = d1++; // d1.operator++(&d1, 0) 整数传什么都可以 只是为了构成重载进行区分
Date d2(2000, 5, 1);
Date d3(2022, 11, 14);
cout<< d3 - d2<< endl;
cout<< d2 - d3<< endl;
}
void TestDate3()
{
// 初始日期错误
Date d1(2022, 11, 32);
Date d2(2022, 2, 29);
}
void TestDate4()
{
Date d1(2022, 11, 20);
// cout<< d1; // 因为函数写在类里面 默认第一个参数是 this(d1) 所以应该是 d1<< cout
// d1.operator<<(cout);
// d1<< cout; // 但是这样写的话有与 cout<< 不合适 ; 所以函数可以写在类外面将参数位置改变
cout<< d1;
Date d2(2000, 5, 1);
Date d3(2022, 11, 14);
cout<< d1<< d2<< d3;
cin >>d1 >>d2 >>d3;
cout<< d1<< d2<< d3;
}
void menu()
{
cout<< "***************************"<< endl;
cout<< "***** 1. 日期加/减天数 *****"<< endl;
cout<< "***** 2. 日期减日期 *****"<< endl;
cout<< "***** 3. 日期->周几 *****"<< endl;
cout<< "***** -1. 退出 *****"<< endl;
cout<< "***************************"<< endl;
}
void TestDate5()
{
const char* WeekDayToStr[] = { "周一", "周二", "周三", "周四", "周五", "周六", "周天" };
Date d1, d2;
int day = 0;
int input = 0;
do
{
menu();
cout<< "请选择:";
cin >>input;
if (input == 1)
{
cout<< "请输入日期及天数(减天数输入负数):";
cin >>d1 >>day;
cout<< "日期加减天数后的日期为:"<< d1 + day<< endl;
}
else if (input == 2)
{
cout<< "请依次输入两个日期:";
cin >>d1 >>d2;
cout<< "相差的天数:"<< d1 - d2<< endl;
}
else if (input == 3)
{
cout<< "请输入日期:";
cin >>d1;
Date start(1, 1, 1);
int n = d1 - start;
int WeekDay = 0; // 初始周一 初始周几存在不确定
//int WeekDay = 5; // 1 1 1 就是周六 但是中间删了 10 天
WeekDay += n;
//cout<< "周"<< WeekDay % 7 + 1<< endl; //
cout<< WeekDayToStr[WeekDay % 7]<< endl; //
}
else
{
cout<< "输入错误,请重新输入:"<< endl;
}
} while (input != -1);
}
void TestDate6()
{
// 只有 指针 和 引用 存在权限的放大和缩小
Date d1(2022, 11, 23);
const Date d2(2022, 11, 24);
d1.Print(); // &d1 Date*
//d2.Print(); // 权限放大,出错 &d2 const Date*
d2.Print();
// Date::operator< Date* const this, const Date
d1< d2; // Date*< const Date*
//d2< d1; // const Date*< Date* 出错,权限放大 所以要加const ==>Date::operator< const
}
int main()
{
//TestDate1U
//TestDate2();
//TestDate3();
//TestDate4();
//TestDate5();
TestDate6();
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章名称:C++类的默认成员函数——赋值重载-创新互联
URL标题:http://pwwzsj.com/article/dhcjjj.html