
◆ 博主名称: 晓此方-CSDN博客
大家好,欢迎来到晓此方的博客。
⭐️C++系列个人专栏:
⭐️踏破千山志未空,拨开云雾见晴虹。 人生何必叹萧瑟,心在凌霄第一峰
目录
0.1概要&序論
みなさん、久しぶりです! ,这里是此方,好久不见!上一篇我们介绍了类的默认成员函数:构造函数和析构函数 。本期此方将为大家带来运算符重载的系统讲解。每一个成功的人都有一段不为人知的时光,这段时光称为"修炼"。加油!类与对象中相对困难的部分即将告一段落啦!
一,运算符重载
1.1运算符重载的意义
运算符都是针对内置类型的,对自定义类型而言,不能简单使用运算符。这样,对于自定义类型的各种运算将无从入手。于是C++增加了运算符重载的概念。
当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。 C++规定类类型对象使用运算符 时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编译报错。
1.1.1运算符重载应当有意义
一个类需要重载哪些运算符,是看哪些运算符重载后有意义 ,比如Date类重载operator-就有意义(了解两个日期之间间隔天数),但是重载operator+就没有意义。
1.2运算符重载的定义
- 运算符重载是具有特殊名字的函数, 他的名字是由operator和后面要定义的运算符 共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体。(前面的流插入流提取。就是一种内置的运算符重载)
-
重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。 一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。
-
万不可连接运算符中不存在的符号进行重载:如operator@。
运算符重载和函数重载没有任何关系 ,但是两个及以上的运算符重载构成函数重载。
1.3运算符重载的创建
1.3.1以Date类为例
cpp
class Date{
pubilc:
Date(int year,int month,int day)
{
_year=year;
_month=month;
_day=day;
}
private:
int _year;
int _month;
int _day;
}
1.3.2创建重载运算符"=="
要让d1==d2,就让d1的所有成员变量==d2所有成员变量。返回值设置为bool类型。传递参数两个Date类类型。
cpp
bool opreator==(Date d1 ,Date d2)
{
if( d1._year==d2._year
&&d1._month=d2._month
&&d1._day=d2._day)
return true;
else
return false;
}
1.3.3无意义创建避免
重载操作符至少有一个类类型参数,不能通过运算符重载改变内置类型对象的含义来构建防御性变编程,如:
cpp
int operator+ (int x, int y)
{
return x-y;
}
1.4运算符重载的调用
1.4.1显式调用
直接把重载后的运算符看作是一个函数,传入参数,如下:
cpp
int main()
{
Date d1(2025,2,23);
Date d2(2025,3,26);
operator==(d1,d2);
return 0;
}
1.4.2隐式调用
把重载后的运算符看作兼容该类类型的运算符,采用运算符语法。
- 对于二元运算符重载:左侧对象传给第一个参数,右侧传输给第二个参数。
- 隐式调用实际上等同于显式调用,会自动转化为显示调用。
cpp
d1==d2;
1.4.3重载为成员函数的调用
下文会讲为什么会重载成成员函数,这里介绍重载为成员函数后的特殊调用方法
如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的 this 指针,因此运算符重载作为成员函数时,参数比运算对象少一个。
cpp
class Date{
pubilc:
bool opreator==(Date d){
if( _year==d._year
&&_month=d._month
&&_day=d._day )
return true;
else
return false;
}
//........
}
显示与隐式调用:
隐式调用方式不变,他会自动转换成显示调用,d1传递给this指针,d2传递给d
cpp
int main()
{
Date d1(2025,2,23);
Date d2(2025,3,26);
d1.operator==(d2);
d1==d2;
return 0;
}
1.4.4调用常见问题:访问限制
由于类的成员变量被private修饰,无法在类外直接调用。
解决办法:
- 最挫的方法:成员变量公有化
- 仿JAVA常用方法:由类提供get()函数
- 后面会讲:友元函数
- 最好的方法:重载为成员函数
方法一: 去掉private修饰,让public修饰的作用域覆盖成员变量 。不建议 ,会让类属性被随意修改。
cpp
class Date{
pubilc:
Date(int year,int month,int day){
_year=year;
_month=month;
_day=day;
}
//private:
int _year;
int _month;
int _day;
}
**方法二:**由类提供get()函数,在对象外调用getyear就可以通过返回值间接得到_year。
cpp
int Getyear()
{
return _year;
}
方法四: 重载为成员函数,**省去一切麻烦,最推荐使用该方法,**大部分的运算符重载函数都是会设计成成员函数。
cpp
class Date{
pubilc:
bool opreator==(Date d2){
if( _year==d2._year
&&_month=d2._month
&&_day=d2._day )
return true;
else
return false;
}
private:
int _year;
int _month;
int _day;
};
1.4.5运算符重载调用优先级
cpp
//..........
bool operator==(const Date& d){
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
//private:
int _year;
int _month;
int _day;
};
bool operator==(const Date& d1, const Date& d2){
return d1._year == d2._year
&& d1._month == d2._month
&& d1._day == d2._day;
}
如果在类的内部和外部同时创建一个相同的运算符重载。
- operator==(d1,d2)显式调用只会调用全局函数。
- d1==d2隐式调用 对调用成员函数还是全局函数会进行重载决议 ,但往往成员函数会获胜。
1.5五大不可重载运算符
- 域访问限定符。"::"
- 计算类型大小。"sizeof"
- 三元操作符。"?:"
- 类访问操作符。"."
- 指向成员变量或成员函数的指针。".*"
原因:
这五个运算符被语言标准明确规定为不可重载 ,原因并不是随意的,而是出于语法完整性、可解析性以及编译期语义安全的系统性考虑。可以从一个统一的原则来理解:
凡是参与"语言语法结构本身"或"编译期语义建模"的运算符,都不可重载。
1.6指向成员变量或成员函数的指针(加餐内容)
上文提到过".*"这个运算符,想必大家都比较陌生,这是C++相比C语言新增的内容。以下给出详细介绍:
1.6.1补充一:成员函数指针
C/C++中一般函数指针举例:
cpp
void (*)(int a,int b);
**成员函数指针类型:**加上了域访问限定符,标志该函数指针来自哪里,是什么类的成员函数。
cpp
void (A::*)(int a,int b);
1.6.2补充二:成员函数指针重命名
重命名:注意函数指针类型的重命名相比一般重命名不同:这里将void (*)(int a,int b)重命名为PF
cpp
typedef void (*PF)(int a,int b);
C/C++中成员函数指针重命名:
cpp
typedef void (A::*PF)(int a,int b);
1.6.3补充三:定义成员函数指针类型变量
定义一个成员函数指针类型的变量:
cpp
void (A::*pf)(int a,int b)=nullptr;//方法一
PF pf=nullptr;//方法二
1.6.4补充四:用成员函数指针回调
取得现有成员函数的指针, 与普通函数指针不同,成员函数的指针取得,需要加上两个步骤:确定类域和取地址。
cpp
pf=&A::func;
**回调函数:**一般函数的回调方式:
cpp
pf=func();
//将函数的指针放入函数指针变量中。
*pf()
//取地址函数指针变量进行回调
成员函数由于函数的第一个参数是this指针 ,但是this指针不能显示传参,所以要一个对象进行辅助,用这个对象调用这个函数。
cpp
A aa;
(aa.*pf)()
于是,就出现了.*运算符。
成员函数的回调在日常代码中使用的非常非常少 。C语言时期学过的qsort函数就是用回调的,后面C++还有很多更好的解决办法,一般的,我们会尽可能避免使用函数指针。
好了,本期内容就到这里,我是此方,我们下期再见。じゃあね〜