写在前面
运算符重载在学的时候着实把我绕进去了,他的实质是用常规运算符实现特殊数据类型的计算。
如
int a = 10 , b = 20;
int c = a + b;
+
可以实现a和b的相加
class Person
{
……
}
Person a , b;
Person c = a + b;
但如果是Person类型 他们还能相加吗
显然编译器不知道 所以我们需要用到重载运算符 让编译器按照我们的方式计算
重载加号运算符
假如我们有一个类
class MyInteger
{
public:
MyInteger(int a, int b)
{
this->m_A = a;
this->m_B = b;
}
private:
int m_A , m_B;
};
int main()
{
Person a(1 , 2);
Person b(3 , 4);
Person c = a + b;
}
我们希望 a和 b 相加 是 其中成员m_A 和 m_B相加
咋办呢
全局函数重载
MyInteger operator+ (const Person& p1 , const Person& p2)
{
MyInterger temp;
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
调用时是这样的
operator+(p1 , p2);
可以简写成
p1 + p2;
这就是重载运算符的好处
由于调用了private成员 我们还要在类里声明
friend MyInteger operator+ (const Person& p1 , const Person& p2);
成员函数里重载
在类中重载其实是一个对象调用成员函数
Person operator+ (const Person& p)
{
Person temp;
temp.m_a = this->m_a + p.m_a;
temp.m_b = this->m_b + p.m_b;
return temp;
}
调用时
p1.operator+(p2);
简写成
p1 + p2;
注意的地方
返回值一定是 类 的类型 否则试试这个
MyInteger p = p1 + p2 + p3;
重载<<
最让我头疼的地方
理解cout
cout 是 ostream 类的一个对象,全局只能有一个
我们平常所用的 cout << 都是经过重载的
比如
cout << 233;
是
operator<<(cout , 233);
的简写
所以我们可以找葫芦画瓢
(返回值先不写) operator<< (ostream& output , const MyInteger& p)
{
output << p.m_A << " " << p.m_B << endl;
return (……);
}
这个时候我们就可以输出
MyInteger p1(10 , 20) , p2(30 , 40);
operator<<(cout , p1);
简写成
cout << p1;
但是 如果是这样 代码还能运行吗 不能了
cout << p1 << p2;
上面这行代码实质是这样的
operator<<(operator<<(cout , p1) , p2);
所以刚才的返回值我们就知道怎么写了
ostream& operator<< (ostream& output , const MyInteger& p)
{
output << p.m_A << " " << p.m_B << endl;
return output;
}
思考
<< 不能用成员函数重载 想一下为什么
因为重载后是 成员.operator<<(cout) , cout 不能放左边
重载递增
实现 a ++ , ++ a等操作
a++是先用a的值作为表达式的值 再让a增加
++a是先让a增加然后作为表达式的值
MyInteger& operator++() //前置重载 返回引用是为了一直对一个数操作
{
m_Integer++;
return *this;
}
为什么返回MyInteger型
因为 ++ ++a
;链式类型
不过这样重载无论你的++放前面还是后面编译器都会认为是 ++a
如果真的想实现a++ 就在重载函数里加上一个占位数(只能为int) 编译器就会认为这是后置地址 不过无法实现链式编程 想想为什么
MyInteger operator++(int) //区分前后置使用占位参数 加上编译器认为是后置递增
{
MyInteger temp = *this;
m_Integer ++;//先记录当时结果
return temp; //不能返回引用 无法实现链式编程
}
重载关系运算符
我们比较时经常用==
!=
这两个同样不能用于特殊类型
重载方式与加减类似
全局
bool operator==(Person a , Person b)
{
if (a.m_a == b.m_a && a.m_b == b.m_b)
return 1;
return 0;
}
不要忘了在类内声明
friend bool operator==(Person a , Person b);
调用
Person p1(10 , 20);
Person p2(10 , 20);
if (p1 == p2) //返回bool类型
{
cout << "p1 和 p2 相等" << endl;
}
重载赋值运算符
有涉及到了浅拷贝和深拷贝的问题
假如类里涉及到了堆区操作
编译器赋值只是浅拷贝 我们必须重载运算符让其变成深拷贝
class Person
{
public:
Person (int age)
{
m_age = new int (age);
}
int* m_age;
//重载赋值运算符
Person& operator=(Person& p)
{
//编译器提供的浅拷贝
//this->m_age = p.m_age
//先判断是否有属性在堆区
if (this->m_age != NULL)
{
delete this->m_age;
this->m_age = NULL;
}
this->m_age = new int(*p.m_age);
return *this;
}
};
返回Person 类型是因为C++支持连续赋值
a = b = c;
重载括号
我们可以重载括号让其使用的时候有特殊操作
class MyPrint
{
public:
//重载函数调用运算符
void operator()(string test)
{
cout << test;
}
};
void test01()
{
MyPrint myprint;
myprint("helloworld"); //由于使用起来非常想函数调用
//成为仿函数
}
使用起来非常像函数调用 所以叫仿函数
仿函数 括号前面是对象
//加法类
class MyAdd
{
public:
int operator()(int a , int b)
{
return a + b;
}
};
void test02()
{
MyAdd a;
int ret = a(100 , 200);
cout << ret;
}
总结
在全局函数重载时
一般类型是 返回类型 operator运算符(变量1,变量2)
一般调用为 operator运算符(变量1,变量2)
一般简写为 变量1 运算符 变量2
在成员函数重载时
一般类型为 返回类型 operator运算符(变量)
一般调用为 对象.operator运算符(变量)
一般简写为 对象 运算符 变量