做网站笔记本2014,免费做团购网站的软件好,商贸企业网站建设设计方案,深圳福田教育目录 运算符重载运算赋值重载和运算赋重载前置和后置,,,,,!运算符重载日期类的实现流插入和流提取的运算符重载总结 运算符重载 C为了增强代码的可读性引入了运算符重载#xff0c;运算符重载是具有特殊函数名的函数#xff0c;也具有其 返回… 目录 运算符重载运算赋值重载和运算赋重载前置和后置,,,,,!运算符重载日期类的实现流插入和流提取的运算符重载总结 运算符重载 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其 返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 注意 不能通过连接其他符号来创建新的操作符比如operator重载操作符必须有一个类类型参数用于内置类型的运算符其含义不能改变例如内置的整型不 能改变其含义作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐 藏的this.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出 现。 先定义一个日期类 先用日期类作为用例
定义一个日期类
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}
//private:int _year;int _month;int _day;
};我们先将日期类的成员改成共有的 写一个运算符重载函数operator
bool operator(const Date d1, const Date d2)
{return d1._year d2._year d1._month d2._month d1._day d2._day;
}可以看见如果写成全局的函数我们必须将成员变量改成共有的所以我们可以将运算符重载函数写成成员函数 代码展示
bool operator(const Date d2){return _year d2._year; _month d2._month _day d2._day;}上面说完运算符重载接下来来讨论一下赋值拷贝函数
由于赋值操作我们改变的是调用这个函数的对象所以我们在参数中可以加上cosnt修饰传值和传引用我们选择传引用最后返回也返回引用这样可以避免调用拷贝构造函数
注意返回值是*this
代码展示
class Date
{
public :
//构造函数Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}
//拷贝构造函数Date (const Date d){_year d._year;_month d._month;_day d._day;}
//赋值拷贝函数Date operator(const Date d){if(this ! d){_year d._year;_month d._month;_day d._day;}return *this;}
private:int _year ;int _month ;int _day ;
};注意赋值拷贝函数和拷贝构造函数类似但是调用的场景是不相同的
注意拷贝构造函数和赋值拷贝函数的调用方式十分相同但是拷贝构造函数调用是在对象不存在时在创建的时候调用拷贝构造函数赋值拷贝函数是对象已经存在了调用的赋值拷贝函数 . 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。注 意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符 重载完成赋值。 既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了还需要自己实 现吗当然像日期类这样的类是没必要的。那么下面的类呢验证一下试试
// 这里会发现下面的程序会崩溃掉这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:DataType *_array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 s1;return 0;
}注意赋值拷贝函数和拷贝构造函数一样当没有malloc和new还有其他动态申请的空间时是不需要写的一旦有动态申请的资源存在时就必须写一个赋值拷贝函数
下图是对上面代码的解释
运算赋值重载和 由于日期类设计到平年和闰年每一个月的日期不同所以我们可以将1到12月的每个月的天数存在一个数组中然后获取每个月的天数这里我们可以只存放平年的然后闰年的天数只有二月是不相同的所以二月我们单独拿出来讨论 注意这个函数我们可以写在类中类中完成的函数默认都是内联函数因为我们后面会经常调用这个函数 inline int GetMonthDay(int year, int month){assert(month 0 month 12);static int monthDayArray[13] { -1,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 monthDayArray[2] 1;}return monthDayArray[month];}注意先判断是否是二月可以增加效率因为二月只有一个月如果每次都判断年的话每次都要进行多余的判断如果先判断是否是二月的话如果是二月才进行后面的判断如果不是二月直接就跳出了 下面来完成运算符重载中的和注意我们可以只写一个然后用去复用 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 12){_month 1;_year;}}return *this;
}
//d110
Date Date::operator(int day)
{Date tmp *this;tmp day;return tmp;//出作用域会销毁所以不能返回引用
}运算赋重载前置和后置 由于运算符重载中运算符只能写在operator的后面所以我们只能利用函数重载来区别后置和前置前置可以直接不给参数后置可以在参数中给一个int和前置作区分。 接下来来写一下日期类的后置和前置注意就是相当于1所以我们可以服用前面的运算符重载
后面写的函数全都是成员函数
//前置
Date Date::operator()
{*this 1;return *this;
}
//为了区分构成重载给后置强行增加了一个int形参
//这里不需要写形参名因为接收值是多少不重要也不需要用
//这个参数仅仅只是一个标志
//后置
Date Date::operator(int)
{Date tmp(*this);*this 1;return tmp;
}上面我们写了操作–操作也同理 –操作
注意–操作我们应该先写-操作和-操作然后去复用这两个函数
Date Date::operator-(int day)
{if (*this 0){return *this (-day);}_day - day;while (_day 0){//借上个月的时间_day GetMonthDay(_year, _month - 1);_month--;if (_month 0){_year--;_month 12;}}return *this;
}
Date Date::operator-(int day)
{Date tmp *this;tmp - day;return tmp;
}
//前置--
Date Date::operator--()
{*this - 1;return *this;
}
//前置--
Date Date::operator--(int)
{Date tmp(*this);*this - 1;return tmp;
},,,,,!运算符重载
注意对于日期类的比较我们可以直接比较年如果年大则返回true如果年相当则比较月如果月大则返回true如果月相当则比较日如果日大则返回true否则剩下的情况则返回false。
代码展示
bool Date::operator(const Date d)//内联函数
{if (_year d._day){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 Date::operator(const Date d)
{return _year d._year _month d._month _day d._day;
}
bool Date::operator(const Date d)
{return *this d || *this d;
}
bool Date::operator(const Date d)
{return !(*this d);
}
bool Date::operator(const Date d)
{return *this d || *this d;
}
bool Date::operator!(const Date d)
{return !(*this d);
}**我们只用写一个剩下的全都可以复用
日期类的实现
Date.h
#pragma once
#includeiostream
#includecassert
using namespace std;class Date
{//友元函数声明friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);
public:Date(int year 1900, int month 1, int day 1);void Print() const;//内联不能声明和定义声明,直接写在类中的默认就是内联函数inline int GetMonthDay(int year, int month){assert(month 0 month 12);static int monthDayArray[13] { -1,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 monthDayArray[2] 1;}return monthDayArray[month];}bool CheckDate();bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator!(const Date d);Date operator(int day);Date operator(int day);Date operator-(int day);Date operator-(int day);//d1;Date operator();//d1//为了区分构成重载给后置强行增加了一个int形参Date operator(int);////--d1Date operator--();//d1--Date operator--(int);int operator-(const Date d);int Getyear(){return _year;}int Getmonth(){return _month;}int Getday(){return _day;}//流插入// 不建议因为Date*this占据了第一个参数位置使用dcout不符合使用习惯//void operator(ostream out);//第一个参数是隐含的this
private:int _year;int _month;int _day;
};
Date.cpp
#includeDate.hbool Date::CheckDate()
{if (_month 1 || _month12 || _day1 || _dayGetMonthDay(_year, _month)){return false;}return true;
}Date::Date(int year, int month, int day)
{_year year;_month month;_day day;if (!CheckDate()){cout 日期错误;}
}
void Date::Print() const //加上这个const之后this指针本身不能改this指针指向的内容也不能改
{cout _year - _month - _day endl;
}
//d1d2
bool Date::operator(const Date d)//内联函数
{if (_year d._day){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 Date::operator(const Date d)
{return _year d._year _month d._month _day d._day;
}
bool Date::operator(const Date d)
{return *this d || *this d;
}
bool Date::operator(const Date d)
{return !(*this d);
}
bool Date::operator(const Date d)
{return *this d || *this d;
}
bool Date::operator!(const Date d)
{return !(*this d);
}
//复用
//思路先加上天上 天满了先加到月上 月满了加到年上
//d110;
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 12){_month 1;_year;}}return *this;
}
//d110
Date Date::operator(int day)
{Date tmp *this;tmp day;return tmp;//出作用域会销毁所以不能返回引用
}//复用
//Date Date::operator(int day)
//{
// Date tmp *this;
// tmp._day day;
// while (tmp._day GetMonthDay(tmp._year, tmp._month))
// {
// tmp._day - GetMonthDay(tmp._year, tmp._month);
// tmp._month;
// if (tmp._month 12)
// {
// tmp._month 1;
// tmp._year;
// }
// }
// return tmp;
//}
//
//Date Date::operator(int day)
//{
// *this *this day;
// return *this;
//}
Date Date::operator-(int day)
{if (*this 0){return *this (-day);}_day - day;while (_day 0){//借上个月的时间_day GetMonthDay(_year, _month - 1);_month--;if (_month 0){_year--;_month 12;}}return *this;
}
Date Date::operator-(int day)
{Date tmp *this;tmp - day;return tmp;
}
Date Date::operator()
{*this 1;return *this;
}
//为了区分构成重载给后置强行增加了一个int形参
//这里不需要写形参名因为接收值是多少不重要也不需要用
//这个参数仅仅
Date Date::operator(int)
{Date tmp(*this);*this 1;return tmp;
}
//前置--
Date Date::operator--()
{*this - 1;return *this;
}
//前置--
Date Date::operator--(int)
{Date tmp(*this);*this - 1;return tmp;
}
int Date::operator-(const Date d)
{Date max *this;Date min d;int flag 1;if (*this d){//赋值拷贝max d;min *this;flag -1;}int n 0;while (min ! max){min;n;}return n * flag;//flag控制的是符号如果前面大就是正的如果后面大就是负数
}流插入和流提取的运算符重载
ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日 endl;return out;
}
istream operator(istream in, Date d)
{cout 请依次输入年月日:;in d._year d._month d._day;return in;
}这里加入了返回值之后就可以进行连续的流插入和流提取了
总结
在本文中我们深入探讨了运算符重载和赋值拷贝函数在C中的应用。通过运算符重载我们可以为自定义类型定义各种操作使得代码更加清晰和易读。而赋值拷贝函数则在对象拷贝和赋值过程中起到了至关重要的作用确保对象之间的正确复制和管理。通过深入理解和熟练应用这些概念我们可以写出更加健壮和高效的代码。 在实践中我们需要注意运算符重载和赋值拷贝函数的使用场景和规范以避免潜在的错误和性能问题。同时对于特定的项目和需求我们也可以进一步扩展和定制这些功能以满足更复杂的应用场景。 最后我希望本文能够帮助读者更好地理解和应用运算符重载和赋值拷贝函数并在实际开发中发挥出它们的作用。让我们继续探索C语言的奥秘写出更加优雅和强大的代码