先看一下操作符重载的基本语法,注意在函数声明时,operator操作符重载关键字后不加空格。
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
class Point
{
public:
Point()
{
m_X = 0;
m_Y = 0;
}
Point(int x, int y):m_X(x),m_Y(y)
{
}
void printPoint(void)
{
cout<<"["<<m_X<<","<<m_Y<<"]"<<endl;
}
//方式2:局部函数声明,通过类的成员函数实现。
Point operator+(Point &another)
{
Point temp;
temp.m_X = m_X+another.m_X;
temp.m_Y = m_Y+another.m_Y;
return temp;
}
public:
int m_X;
int m_Y;
};
#if 0
//方式1:全局函数声明。在函数声明时,operator操作符重载关键字后不加空格。
Point operator+(Point &p1, Point &p2)
{
Point temp;
temp.m_X = p1.m_X+p2.m_X;
temp.m_Y = p1.m_Y+p2.m_Y;
return temp;;
}
#endif
int main(void)
{
Point a(1, 1);
Point b(2, 2);
Point c = a + b;//这句话在执行的时候,就等价于 全局:operator+(a, b)
// 局部:a.operator+(b)
c.printPoint();
return 0;
}
关于重载的规则
(1)c++不允许用户自己定义新的运算符,只能对已有的c++运算符进行重载
(2)c++有些运算符不可重载
下面是可重载的运算符列表:
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于),<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),--(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
下面是不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符,取值操作符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号
(3)运算符重载不能改变运算符对象(即操作数)的个数
(4)重载不能改变运算符的优先级别
(5)重载不能改变运算符的结合性
(6)重载运算符的函数不能有默认参数
(7)重载的运算符,必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。
重载前++
下面额外补充一个左移右移操作符的重载
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
class Point
{
public:
Point()
{
m_X = 0;
m_Y = 0;
}
Point(int x, int y):m_X(x),m_Y(y)
{
}
void printPoint(void)
{
cout<<"["<<m_X<<","<<m_Y<<"]"<<endl;
}
#if 0
//这样调用的话,左边的参数必须是对象
//Point A;
//A<<cout;
ostream & operator<<(ostream &os)
{
os<<"["<<m_X<<","<<m_Y<<"]"<<endl;
return os;
}
#endif
public:
int m_X;
int m_Y;
};
#if 1
//注意左移右移操作符不建议作为类的成员函数重载定义,否则会出现逻辑使用偏差
ostream & operator<<(ostream &os, Point &p)
{
os<<"["<<p.m_X<<","<<p.m_Y<<"]"<<endl;
return os;
}
istream & operator>>(istream &is, Point &p)
{
cout<<"x:";
is>>p.m_X;
cout<<"y:";
is>>p.m_Y;
return is;
}
#endif
int main(void)
{
Point a(1, 1);
Point b(2, 2);
cin >> a;
cin >> b; //相当于调用operator>>(cin, b)
cout << a << b; //相当于调用operator<<(cout, a),返回os,然后再调用operator<<(cout, b)
return 0;
}
运行结果
等号操作符重载,深拷贝操作
#include <iostream>
#include <cstring>
using namespace std;
class teacher
{
public:
teacher(int id, const char *name)
{
cout<<"teacher(int id, const char *name) ...."<<endl;
m_id = id;
m_name = new char[strlen(name)];
if (NULL != m_name)
{
strcpy(m_name, name);
}
}
~teacher()
{
cout<<"~teacher() ...."<<endl;
if (NULL != m_name)
{
delete m_name;
}
}
void Pinrt()
{
cout<<"id="<<m_id<<", name="<<m_name<<endl;
}
teacher(const teacher &another)
{
m_id = another.m_id;
m_name = new char[strlen(another.m_name)];
if (NULL != m_name)
{
strcpy(m_name, another.m_name);
}
}
teacher &operator=(const teacher &another)
{
if (this == &another)
{
return *this;
}
if (this->m_name != NULL)
{
delete this->m_name;
this->m_name = NULL;
this->m_id = 0;
}
//深拷贝动作
this->m_id = another.m_id;
this->m_name = new char[strlen(another.m_name)];
if (NULL != this->m_name)
{
strcpy(this->m_name, another.m_name);
}
return *this;
}
#if 0
//默认拷贝构造的实现
teacher(const teacher &another)
{
m_id = another.m_id;
m_name = another.m_name;
}
#endif
private:
int m_id;
char *m_name;
};
int main(void)
{
teacher t1(10, "zhang3");
t1.Pinrt();
teacher t2(20, "li4");
t2 = t1; //如果没有重载=运算符,执行的是默认的=赋值,是浅拷贝,将zhang3的地址直接赋值给t2的m_name,析构的时候报错。
t2.Pinrt();
teacher t3(30, "wang5");
//也可以实现连等操作
t2 = t1 = t3;
t2.Pinrt();
return 0;
}
注意代码中的注释和理解,堆上的空间时如何申请和释放的。