为什么使用赋值运算符重载函数?
对于系统的所有操作符,一般情况下,只支持基本数据类型和标准库中提供的class,对于用户自己定义的class或struct的对象,如果想支持基本操作,比如比较大小,判断是否相等,等等,则需要用户自己来定义关于这个操作符的具体实现。
比如,判断两个人是否一样大,我们默认的规则是按照其年龄来比较,所以,在设计person 这个class的时候,我们需要考虑操作符==,而且,根据刚才的分析,比较的依据应该是age。那么为什么叫重载呢?这是因为,在编译器实现的时候,已经为我们提供了这个操作符的基本数据类型实现版本,但是现在他的操作数变成了用户定义的数据类型class,所以,需要用户自己来提供该参数版本的实现
双目操作符重载
赋值类双目操作符重载
成员函数方式
#include <iostream> //复数类 class Complex{ public: Complex(int r=0,int i=0):m_r(r),m_i(i){ } void print(void)const{ std::cout<<m_r<<'+'<<m_i<<'i'<<' '; } //c1+=c2==>c1.operator+=(c2) c1就是自身 Complex& operator+=(const Complex& c ){ m_r+=c.m_r; m_i+=c.m_i; return *this; } private: int m_r; //实部 int m_i; //虚部 }; int main() { Complex c1(10,20); Complex c2(5,8); Complex c3 =c1+=c2; c3.print(); return 0; }
全局函数方式
#include <iostream> //复数类 class Complex { public: Complex(int r = 0, int i = 0) :m_r(r), m_i(i) { } void print(void)const { std::cout << m_r << '+' << m_i << 'i' << ' '; } friend Complex& operator-=(Complex& l, const Complex& r); private: int m_r; //实部 int m_i; //虚部 }; //c1-=c2==>operator-=(c1,c2) Complex& operator-=(Complex& l, const Complex& r) { l.m_r -= r.m_r; l.m_i -= r.m_i; return l; } int main() { Complex c1(10, 20); Complex c2(5, 8); c1 -= c2; c1.print(); return 0; }
计算类双目操作符重载
成员函数方式
L#R的表达式可以被编译器处理为“L.operator#(R)”成员函数调用形式,该函数的返回值就是表达式的结果
比如:c1+c2 c1.operator+(c2)
#include <iostream> //复数类 class Complex{ public: Complex(int r=0,int i=0):m_r(r),m_i(i){ } void print(void)const{ std::cout<<m_r<<'+'<<m_i<<'i'<<' '; } //c1+c2==>c1.operator+(c2) c1就是自身 const Complex operator+(const Complex& c) const{ //+操作符重载 //第一个const: 保证返回值是右值 //第二个const:支持常量型右操作数 //第三个const: 支持常量型左操作数 Complex res(m_r+c.m_r,m_i+c.m_i); return res; } private: int m_r; //实部 int m_i; //虚部 }; int main() { Complex c1(10,20); Complex c2(5,8); c1.print(); c2.print(); Complex c3=c1+c2;//调用+重载函数 c3.print(); return 0; }
全局函数方式
L#R的表达式可以被编译器处理为“operator#(L,R)”全局函数调用形式,该函数的返回值就是表达式的结果
#include <iostream>
//复数类
class Complex{
public:
Complex(int r=0,int i=0):m_r(r),m_i(i){ }
void print(void)const{
std::cout<<m_r<<'+'<<m_i<<'i'<<'
';
}
private:
int m_r; //实部
int m_i; //虚部
//友元函数:把一个全局函数声明为友元函数, 友元函数可以访问类中任何成员
friend const Complex operator-(const Complex& l,const Complex& r);
};
//重载- :全局方式
//c2-c1==>operator-(c2,c1)
const Complex operator-(const Complex& l,const Complex& r){
Complex res(l.m_r-r.m_r,l.m_i-r.m_i);
return res;
}
int main()
{
Complex c1(10,20);
Complex c2(5,8);
c1.print();
c2.print();
Complex c3=c1-c2;
c3.print();
return 0;
}
单目操作符重载
计算单目操作符
比如:-(负) ~(位反)
成员函数实现
#include <iostream> class Integer { public: Integer(int i = 0) :m_i(i) { } void print(void)const { std::cout << m_i << std::endl; } //Integer j = -i ==>i.operator-() const Integer operator-(void)const { //没有形参:操作数就是自身 Integer res(-m_i); return res; } private: int m_i; }; // operator int main() { Integer i(100); Integer j = -i; j.print(); return 0; }
全局函数实现
#include <iostream> class Integer { public: Integer(int i = 0) :m_i(i) { } void print(void)const { std::cout << m_i << std::endl; } //Integer j = -i ==>i.operator-() friend const Integer operator~(const Integer& i); private: int m_i; }; const Integer operator~(const Integer& i) { Integer res(i.m_i* i.m_i); return res; } int main() { Integer i(100); Integer j = ~i; j.print(); return 0; }
自增减单目操作符
比如:++ --
#include <iostream> class Integer { public: Integer(int i = 0) :m_i(i) { } void print(void)const { std::cout << m_i << std::endl; } /* 左值:有特定的地址,其值可以修改 a++ 不可以作为左值;++a 可以作为左值 a++的意思是先复制一份临时数据出来参与周边环境的运算,再自加变量a,可见a++用来参与运算的是一份复制出来的临时数据,这个数据是临时存在而没有固定地址的,不是一个真正的变量,所以只能是右值 ++a的意思是先自加变量a,再将变量放到周边环境参与运算,那么++a用来参与运算的是有具体地址的变量,所以++a是可以作为左值使用的 哑元:一个函数的参数 只有类型 没有名字 则这个参数称之为哑元 后缀操作符重载会多一个哑元参数,用来与前缀操作符重载的区分 */ //前++ 成员函数形式 Integer& operator++(void) { //没有形参:操作数就是自身 ++m_i; return *this; } friend Integer& operator--(Integer& i); //后++ 成员函数形式 const Integer operator++(int) { //参数:哑元参数 Integer old = *this; ++m_i; return old; } friend const Integer operator--(Integer& i,int); private: int m_i; }; //前-- 全局函数形式 Integer& operator--(Integer& i) { --i.m_i; return i; } //后-- 全局函数形式 const Integer operator--(Integer& i, int) { //参数:哑元参数 Integer old = i; --i.m_i; return old; } int main() { Integer i(100); Integer j=++i; j.print(); return 0; }
输入输出操作符重载(<< >>)
#include<iostream> class Complex { public: Complex(int r,int i):m_r(r),m_i(i){} //<< 操作符重载函数 // cout<<c1 ==>operator<<(cout,c1) friend std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.m_r << '+' << c.m_i << 'i'; return os; } //>> 操作符重载函数 // cout<<c1 ==>operator>>(cout,c1) friend std::istream& operator>>(std::istream& is, Complex& c) { std::cout << "输入实部:"; is >> c.m_r; std::cout << "输入虚部:"; is >> c.m_i; return is; } private: int m_r;//实部 int m_i;//虚部 }; int main() { Complex c1(10, 20); Complex c2(1, 2); std::cout << c1 << std::endl; //"10+20i" std::cin >> c2; std::cout << c2 << std::endl; return 0; }
可见,当用一个非类A的值(如上面的int型值)为类A的对象赋值时:
①如果匹配的构造函数和赋值运算符重载函数同时存在,会调用赋值运算符重载函数
②如果只有匹配的构造函数存在,就会调用这个构造函数
重载运算符的规则:
重载运算符的函数不能有默认的参数:不然就改变了运算符参数的个数
重载运算符的函数参数至少有一个是本类的对象或引用,不能全部都是C++的基本类型