运算符重载
-
运算符重载的概念
-
非类的成员函数实现运算符重载
-
类的成员函数实现运算符重载
-
重载运算符的意义
-
运算符重载的限制
-
运算符重载的原则
-
运算符重载的正确姿势
运算符重载的概念
运算符重载的概念
在OOP编程中,万物皆对象,比如我们学习过的std:string对象,能够像普通类型一样实现加减乘除呢
std:string str=“大家好!";
str=str+“才是真的好!";
要实现这个功能我们就要对运算符+重新进行设计,当我们的对象进行+运算时不再是编译器默认的+预算,而是进入我们指定的函数
这种重新设计运算符规则的技术就称为运算符重载
语法:返回类型 operator运算符()
//例如
bool operator<(const Role& role);
class Person
{
unsigned short Age;
public:
Person(unsigned short _Age) :Age{ _Age }
{}
};
int main()
{
Person Man(20);
Person Woman(50);
if(Man<Woman)//报错:没有与这些操作数匹配的<运算符
}
非类的成员函数实现运算符重载
class Person
{
friend bool operator < (Person& psa, Person& psb);//友元函数使其可以访问类的私有成员
unsigned short Age;//私有成员变量
public:
Person(unsigned short _Age) :Age{ _Age }
{}
};
bool operator < (Person& psa, Person& psb)
{
return psa.Age < psb.Age;
}
int main()
{
Person Man(20);
Person Woman(50);
if (operator<(Man, Woman))std::cout << "女人年纪大";//写法1:相当于将其看成一个普通函数名
if (Man<Woman)std::cout << "女人年纪大" << std::endl; //写法2:直接用小于号
}
————————————————————————————————————————————————————————————————————————————————
//不用友元函数的写法
class Person
{
unsigned short Age;
public:
Person(unsigned short _Age) :Age{ _Age }
{}
unsigned short GetAge()
{
return Age;
}
};
bool operator < (Person& psa, Person& psb)
{
return psa.GetAge() < psb.GetAge();
}
类的成员函数实现运算符重载
class Person
{
unsigned short Age;
public:
Person(unsigned short _Age) :Age{ _Age }
{}
bool operator>(Person& person); //类的成员函数实现运算符重载
};
bool Person::operator>(Person& person)
{
return Age > person.Age;
}
int main()
{
Person Man(20);
Person Woman(50);
if(Man.operator>(Woman))std::cout << "男人年纪大";//写法一:相当于将其看成普通函数
if (Man>Woman)std::cout << "男人年纪大" << std::endl;//写法二:直接用>
}
重载运算符的意义
-
让类也支持原生的运算比如+-*/
-
提升对程序的控制权比如重载new delete new[] delete[]
备注:
运算符重载的主要目的是为了让目标代码更方便使用和维护,而不是提升开发效率,重载运算符未必能提升开发效率
运算符重载的限制
-
不能自创运算符比如===,=<>=只能重载现有运算符
-
以下运算符不能重载
-
对象访问运算符.例如 user.hp
-
作用域解析运算符:: 例如std::cout
-
求大小的运算符sizeof 例如sizeof(int)
-
条件运算符 ? : 例如b=a>c?100:200
-
不能修改运算符本身的优先级,相关性
-
在C++17后,也不能修改运算符的操作数的计算顺序,在C++17前,编译器可以自由选择如何计算(未定义行为)
-
除了delete/delete[]和new/new[]外,不能对原生数据类型的其他运算符进行重载,比如把char类型的+定义为-
int operator+(int a, int b)//错误,非成员运算符要求类类型或枚举类型的参数
{}
-
除了new和delete以外,其他运算符的arity (运算符关联的操作数的个数或者是关联的参数)一律不能修改
运算符重载的原则
-
不要改变运算符本身的意义, 比如把加法重载为减法
-
不建议重载 逻辑运算符&& ||,取址运算符& 逗号运算符,
备注:重载后的逻辑运算符将不会进行短路测试,在C++17标准前,编译器可以自由决定先计算左操作数还是右操作数 , 在C++17后计算的顺序规定为先计算左再计算右
短路测试:a&&b,如果a不成立,则不会测试b
运算符重载的正确姿势
语法
-
二元运算符的重载
利用全局函数 返回类型 operator 运算符 (类型 左操作数, 类型 右操作数)
利用类的成员函数 返回类型 operator 运算符 (类型右操作数)
-
一元运算符的重载
利用全局函数返回 返回类型 operator 运算符 (类型 操作数)
利用类的成员函数 返回类型 operator 运算符 ()
正确姿势:
-
有的运算符只能重载为类的成员函数,有些运算符只能重载为全局函数,有些运算符既可以重载为类的成员函数又可以重载为全局函数,
如果一个运算符既可以重载为成员函数又可以重载为全局函数,我们一般推荐重载为类的成员函数,因为类的成员函数可以是虚函数,单全局函数不能是虚函数,
如果这个运算符不修改对象,应该将这个成员函数限定为const
-
运算符重载的参数一般可以传递值或者引用,大部分情况下,能够传递引用就不要传递值,
对于不会修改的值最好是限定为const,
某些时候要擅用使用右值引用&&作为参数
-
运算符重载的返回值一般来说可以是任何类型,但是尽量要符合运算符的原意,
比如把>运算符返回指针类型,把+返回bool类型,都不是很好的选择