本章重点是类设计技术,而不是通用原理。
C++的重点是多使用。
正如我之前写了这么多的学习笔记一样,几乎绝大部分的代码,都是我根据书上的知识,然后理解自行再创造写下的。虽然遇见了不少问题,但解决后,下次再遇见这类情况,解决起来很轻松,绝大多数都可以直接靠记忆书写代码,即使个别忘记了,回头翻一番笔记,基本也能解决,需要靠百度去解决的,已经很少了。
运算符重载是一种形式的C++多态(就像函数重载那样,同名但调用不同的函数)。
要重载运算符,需要使用被称为运算符函数的特殊函数形式。运算符函数格式如下:
operator 运算符 (argument-list);
例如:operator +(); 表示重载加号运算符,而operator -()表示重载减号运算符。
其中,运算符必须是有效的C++运算符,而不是是自己捏造的(例如+-*/之类就是有效的,而@就是无效的)。
但需要注意的是,定义运算符有时需在类中定义(非必须,具体看下面的运算符重载的限制),对该类对象有效。运算符前面是的调用该方法的对象,参数中是被调用的对象。
例如:
class Mm
{
int a;
public:
...... ;
Mm operator + (const Mm &bb)
{return this->a + bb.a;}
}
这里实际上就是把+号运算符重载为对对象有用的加号运算符了。
如代码:
#include<iostream>
#include<string>
class Skill //技能类
{
std::string name; //技能名称
double jilv; //几率
double dam; //伤害
public:
Skill(std::string name_ = "无技能", double jilv_ = 0.0, double dam_ = 0.0) { name = name_;jilv = jilv_;dam = dam_; } //默认构造函数,默认几率和伤害都为0
void show();
Skill operator +(const Skill&b); //技能融合函数,将2个技能融合起来变成第三个技能
};
int main()
{
using namespace std;
Skill one("拔刀斩", 20, 500);
Skill two("半月斩", 15, 400);
one.show();
two.show();
Skill three = one + two; //新对象为两个对象之和
cout << "技能已融合!新技能get!" << endl;
three.show();
system("pause");
return 0;
}
void Skill::show()
{
std::cout << "技能:" << name << " 的发动几率为 " << jilv << " %,伤害为: " << dam << " 点。" << std::endl;
}
Skill Skill::operator+(const Skill&b)
{
Skill another;
another.name = name; //名字延续加号前的
another.jilv = (jilv + b.jilv)*1.25; //几率为两个几率之和,乘以1.2
if (another.jilv > 100)another.jilv = 100; //如果几率大于100,则为100
another.dam = dam + b.dam*0.5; //伤害为第一个伤害加上第二个伤害的一半
return another; //返回对象(不是引用)
}
输出:
技能:拔刀斩 的发动几率为 20 %,伤害为: 500 点。
技能:半月斩 的发动几率为 15 %,伤害为: 400 点。
技能已融合!新技能get!
技能:拔刀斩 的发动几率为 43.75 %,伤害为: 700 点。
请按任意键继续. . .
总结:
①运算符重载的关键,是运算符左边的调用重载函数,右边的作为参数,所以在码代码的时候,需要注意顺序。
例如,one+two时,按照类方法,新对象three是one的名字,如果是two+one,新对象three是two的名字。
当然,具体是什么,根据函数定义来决定。
运算符重载的限制:
多数C++运算符(参见表11.1,如下图,不过看不清……)都可以用这样的方式重载。
ps:图看不清,不传了。具体请看书(最好看实体书,pdf版不是很清楚,不过大部分都可以重载)但也有一些限制,例如:重载的运算符不必是成员函数,但必须至少有一个操作数是用户定义的类型。
具体限制如下:
①重载后的运算符,必须至少有一个操作数是用户定义的类型(否则不知道你使用的是运算符重载,在运算符重载的函数定义里,也容易出问题),这将防止用户为标准类型重载运算符。
因此,不能把减法运算符重载为2个标准类型(如int或者double)的值的和,而不是他们的差。
②使用运算符时不能违反运算符原来的句法规则。例如,+-*/以及%这五种运算符,需要两个数来参与。你不能只给他用一个数。例如a+b是可以的,但是+a这种是不行的。而像地址运算符&就是只对一个数使用,如&dizhi。
另外,运算符即使被重载,其运算优先级也与原来的运算符的优先级相同,例如a+b/c,即使对+进行运算符重载,也依然是先计算b/c,再计算a+ (b/c)的结果。
③不能创建新的运算符,只能用已有的
④不能重载下面的运算符。
(1)sizeof sizeof运算符
(2). ←这是一个句号,成员运算符,比如结构名.结构内变量
(3).* ←句号和乘号,成员指针运算符(没见过)
(4):: ←两个冒号,作用域解析运算符
(5)?: 条件运算符,比如: a>b?c:d
(6)typeid ←一个RTTI运算符(没见过)
(7)const_cast ←强制类型转换运算符(没见过这种用法)
(8)dynamic_cast ←强制类型转换运算符(没见过这种用法)
(9)reinterpret_cast ←强制类型转换运算符(没见过这种用法)
(10)static_cast ←强制类型转换运算符(没见过这种用法)
而上面那个图片中的运算符,基本都可以用(反正大部分都能用,不能用的是少数)。
⑤大部分运算符:可以通过成员、非成员函数进行重载;
以下几个运算符,只能通过成员函数进行重载:
(1)= ←赋值运算符
(2)() ←函数调用运算符
(3)[] ←下标运算符(为什么叫下标?)
(4)-> ←通过指针访问类成员的运算符(不懂,是指this->私有成员这样么?)
⑥运算符重载最好遵循一般逻辑,例如不要把加法运算符(+)重载为两个对象各个值的差这种违反直觉的事情。
⑦重载运算符面对不同对象时,需要定义不同类型的重载运算符函数。
例如,一个对象 + 另一个对象,和一个对象 + 一个int值/double值,是不能使用同一个函数的。
如代码:
#include<iostream>
#include<string>
class Skill //技能类
{
std::string name; //技能名称
double jilv; //几率
double dam; //伤害
public:
Skill(std::string name_ = "无技能", double jilv_ = 0.0, double dam_ = 0.0) { name = name_;jilv = jilv_;dam = dam_; } //默认构造函数,默认几率和伤害都为0
void show()const;
Skill operator +(const Skill&b)const; //技能融合函数,将2个技能融合起来变成第三个技能
void operator*=(const double &b); //技能增强函数,重载运算符*=
void operator/=(const double &b); //另一种形式的增强,通过降低概率增加伤害,重载运算符/=
};
int main()
{
using namespace std;
Skill one("拔刀斩", 20, 500);
Skill two("半月斩", 15, 400);
one.show();
two.show();
Skill three = one + two; //新对象为两个对象之和
cout << "技能已融合!新技能get!" << endl;
three.show();
cout << "现将增强你的技能,增强发动几率和伤害,增加比例为1.5。" << endl;
three *= 1.5; //重载*=运算符
three.show();
cout << "现在将降低概率,增强伤害,系数为:2" << endl;
three /= 2; //重载/=运算符
three.show();
cout << "bye." << endl;
system("pause");
return 0;
}
void Skill::show()const
{
std::cout << "技能:" << name << " 的发动几率为 " << jilv << " %,伤害为: " << dam << " 点。" << std::endl;
}
Skill Skill::operator+(const Skill&b)const
{
Skill another;
another.name = name; //名字延续加号前的
another.jilv = (jilv + b.jilv)*1.25; //几率为两个几率之和,乘以1.2
if (another.jilv > 100)another.jilv = 100; //如果几率大于100,则为100
another.dam = dam + b.dam*0.5; //伤害为第一个伤害加上第二个伤害的一半
return another; //返回对象(不是引用)
}
void Skill::operator*=(const double &b)
{
jilv *= b; //几率和伤害都乘以系数
dam *= b;
}
void Skill::operator/=(const double &b)
{
jilv /= b; //几率除系数
dam *= b; //伤害乘系数
}
输出:
技能:拔刀斩 的发动几率为 20 %,伤害为: 500 点。
技能:半月斩 的发动几率为 15 %,伤害为: 400 点。
技能已融合!新技能get!
技能:拔刀斩 的发动几率为 43.75 %,伤害为: 700 点。
现将增强你的技能,增强发动几率和伤害,增加比例为1.5。
技能:拔刀斩 的发动几率为 65.625 %,伤害为: 1050 点。
现在将降低概率,增强伤害,系数为:2
技能:拔刀斩 的发动几率为 32.8125 %,伤害为: 2100 点。
bye.
请按任意键继续. . .