运算符重载
对于内置的数据类型,编译器知道如何运算,但是对于自定义的类型,编译器并不知道如何进行运算,因此需要自定义运算符的功能,这就是运算符重载。
加号运算符重载
使用 operator+ 成员函数实现运算符 + 的重载。
其本质上是 p3 = p1 + p2; == p3 = p1.operator+(p2);
class ppp
{
public:
ppp operator+(const ppp &p);
ppp();
ppp(int a, int b);
public :
int m_a;
int m_b;
};
ppp ppp::operator+(const ppp &p)
{
ppp temp;
temp.m_a = m_a + p.m_a;
temp.m_b = m_b + p.m_b;
return temp;
}
ppp::ppp()
{
;
}
ppp::ppp(int a, int b)
{
m_a = a;
m_b = b;
}
int main()
{
ppp p1(3,4);
ppp p2(1,0);
ppp p3 = p1 + p2;
cout << p3.m_a << " "
<< p3.m_b << endl;
}
也可以用全局函数实现重载:p3 = operator+(p1 ,p2) 。
左移运算符的重载
如果我们想像输出一个整型那么简单地输出类对象的所有成员的话,可以重载左移运算符。
但是不建议使用成员函数重载左移运算符。
ppp::operator<<(const ppp &p);
//如果这么设计重载左移运算符,等价于 p.operator<<(p) 对象太多,不符合要求
ppp::operator<<(cout);
//这么定义的话,会导致输出写成 p << cout 也不符合我们的要求
//我们希望能写成 cout << p;
所以建议使用全局函数重载<<运算符。
decltype(cout) &operator<<(decltype(cout) &cout, ppp &p)
{
cout << p.m_a << " " << p.m_b;
return cout;
}
为了保证能够链式输出,返回类型必须写成输出流,由于输出流全局只有一个,所以需要返回一个引用;写入时也必须传入引用。
cout 的类型是 ostream。
如果有需求是输出类的所有成员,那么这个重载函数必须写成该类的友元。
递增递减运算符
递增递减运算符同理,因此只展示递增。
//重载前置++运算符,全局函数版本
ppp &operator++(ppp &p)
{
p.m_a++;
return p;
}
//成员函数版本
ppp & ppp::operator++()
{
m_a++;
return *this;
}
对于整型来说,前置++先把变量加1再返回该变量,因此返回的和输入的应当是同一个对象,故而输入输出均使用了类引用类型。
//重载后置++,全局函数版本
ppp operator++(ppp &p, int)
{
ppp temp = p;
p.m_a++;
return temp;
}
//成员函数版本
ppp ppp::operator++(int)
{
ppp temp = *this;
p.m_a++;
return temp;
}
首先,前置递增与后置递增的区别是占位参数int 。
其次,后置递增由于先返回自身,所以必须采取临时变量存储原先的值,所以不能输出引用类型。因为局部变量在成员函数执行完后就会被销毁。
赋值运算符重载
事实上,当一个类被创建的时候,编译器除了会给出几个默认的构造函数,还会默认给一个重载的赋值运算,当然,它赋值的方式也是值传递。因此还会出现深浅拷贝的问题,因此如果成员有指针类型地话,必须重写赋值运算符。
ppp& ppp::operator=(ppp &p)
{
//先检查地址为空,不为空就先释放掉
if (m_a != NULL)
{
delete m_a;
m_a = NULL;
}
//深拷贝
m_a = new int(*(p.m_a));
//为了连等操作,需要返回自身
return *this;
}
关系运算符重载
//重载 == 运算符
bool operator==(ppp &p)
{
if(this->m_a == p.m_a)
{
return true;
}
return false;
}
函数调用运算符重载(仿函数)
对函数调用运算符重载地话称为仿函数,它的运用特别像函数。
class myAdd
{
public:
int operator()(int a, int b)
{
return a+b;
}
};
myAdd aa;
int ret = aa(100,10);
cout << ret << endl;