ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C++:运算符重载

C++:运算符重载 引言本文围绕C类与对象板块中的运算符重载展开系统讲解其必要性、核心语法与常见注意事项。为什么要重载运算符假如你定义了一个类它表示“年/月/日”这样的日期class Date { public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } void Print() { cout _year / _month / _day endl; } private: int _year; int _month; int _day; };如果你想在2026/8/31这个日期上加上60天或者想用两个日期相减以计算它们之间的间隔但原本的“”与“-”运算符并不对自定义类类型有效所以我们为了功能或工程需要必须给运算符赋予新的功能这就是运算符重载的必要性。运算符重载函数operatoroperator与普通运算符重载想要重载运算符需要运算符重载函数它由名字operator加上需要重载的运算符组成它的参数和需要重载的运算符的操作数一样多且参数的顺序和运算符的操作数的顺序一样。我们拿重载“日期类”的“-”为例。“-”是一个二元运算符我们想实现“日期” - “日期” 天数并且把这个重载作为类的成员函数那么需要在operator前加上“-”参数分别是“减数”“被减数”返回值就是int天数声明就是这样int operator-(const Date d);我们知道成员函数的第一个参数是隐藏的“ Date* const this”——“被减数”而第二个“减数”就是const Date d。需要注意的是1.重载的运算符的优先级和结合性与原先一致。2.operator无法通过链接语法中没有的操作符来创建新的操作符3.operator重载必须至少有一个类类型参数不能改变内置操作符原本的含义比如不能int operator(int x, int y))4.一个类需要重载那些操作符应视情况而定比如日期类重载减法以计算间隔没问题但是重载乘法是没有意义的。5.重载或者--时C通过规定operator是否有带有int参数来区分重载的是前缀还是后缀。带有int参数即为后缀没有就是前缀。Date operator();//重载前缀 Date operator(int);//重载后缀Date Date::operator() { *this 1; return *this; } Date Date::operator(int) { Date tmp *this; *this 1; return tmp; }虽然都是自增但后缀需要返回自增前的值所以我们只能先用临时的tmp记录旧值自增后返回故而返回类型为Date而不是Date6.有些运算符无法被重载像是sizeof .*成员指针解引用7.若要重载“和“建议重载为全局函数否则用起来很怪这点我们详细讲讲。如果我想实现“cout 日期类”直接打印出日期一开始可能会想到的是把它作为成员函数但问题在于成员函数的第一个参数永远是“ Date* const this那你只能ostream operator(ostream out) { return out d._year / d._month / d._day endl; }这样先不说那几个成员函数的访问问题用起来也很诡异因为你必须反过来int main(){ Date d1(2026,8,31); d1 cout; return 0 }这显然不是我们需要的。最好的方法是把它设为全局函数同时在类中进行“友元声明”友元声明可以运行函数访问private中的参数而全局函数就能改变日期类类型参数的位置。//Date.h class Date { //友元函数声明 friend istream operator(istream in, Date d);//输出重载 friend ostream operator(ostream out, const Date d);//输入重载 public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } private: int _year; int _month; int _day; }; //全局函数 ostream operator(ostream out, const Date d); istream operator(istream in, Date d); //Date.cpp ostream operator(ostream out, const Date d) { return out d._year / d._month / d._day endl; } istream operator(istream in, Date d) { int year 0; int month 0; int day 0; cout 请输入日期:; in year month day; if (!isValidDate(year, month, day))//检查输入的日期是否合法 { cout 输入的日期无效 endl; return in; } d Date(year, month, day); return in; }赋值运算符重载赋值运算符重载是一个默认成员函数用于完成两个已存在的对象之间的赋值它和拷贝构造的区别在于后者是要给一个正在创建的对象赋值。默认成员函数在没有自己实现时编译器会自己创建一个对于内置类型成员进行浅拷贝而对于自定义类型则会调用它的赋值重载函数。这种函数自然和拷贝构造一样有个老生常谈的规矩对于像Date日期这样的类默认的赋值重载没什么问题但对于像Stack这样成员变量指向了空间那就要自己实现。通常而言如果一个类实现了析构并释放了资源那么赋值重载务必要自己实现。const成员函数被const修饰的成员函数长这样const放在参数列表的后面void Print() const { cout _year - _month - _day endl; }这里的const本质上是修饰隐含的this指针把 Date* const this 变成了 const Date* const this 。二者的含义分别是this的指向不可改变。this指向的东西不可改变取地址运算符重载对取地址的重载是一个非常非常大的雷点总结起来一句话若非极其特殊的场景否则千万不要对取地址运算符进行重载因为重载后可能无法返回对象的真实地址这非常反直觉如果一定要重载记得const和非const的版本都要实现。
返回列表