c++中的操作符重载

时间:2022-02-03 17:46:50

  来讲讲c++强大特性之一,操作符重载。
  中学时的数学课程学习的复数,其形式为:a + bi(a、b均为实数),其中a称为实部,b称为虚部,i称为虚数单位。复数和实数一样,可以进行加减乘除等运算。那么我们可以构建一个复数类,如下。

class ComplexNumber
{

public:
int a; //实部
int b; //虚部
};

  根据复数运算规则,两个复数可以相加,其运算规则为实部加实部,虚部加虚部,那么下面代码可行?

class ComplexNumber
{

public:
int a; //实部
int b; //虚部

ComplexNumber(int a, int b)
{
this->a = a;
this->b = b;
}
};

int main(void)
{
ComplexNumber c1(1, 2);
ComplexNumber c2(5, 9);
ComplexNumber c3 = c1 + c2;

printf("c3.a = %d, c3.b = %d\n", c3.a, c3.b);

return 0;
}

编译自然报错:
c++中的操作符重载

加法操作符只能针对于实数之间,怎么可以用于对象之间。
为实现复数相加功能,我们可以定义一个成员函数Add(),专门实现此功能:

class ComplexNumber
{
private:
int a; //实部
int b; //虚部

public:
ComplexNumber(int a, int b)
{
this->a = a;
this->b = b;
}

ComplexNumber Add(ComplexNumber& c1, ComplexNumber& c2)
{
ComplexNumber ret(c1.a + c2.a, c1.b + c2.b);
return (ret);
}

int getA()
{
return a;
}

int getB()
{
return b;
}
};

int main(void)
{
ComplexNumber c1(1, 2);
ComplexNumber c2(5, 9);
//ComplexNumber c3 = c1 + c2;

ComplexNumber c3 = c1.Add(c1, c2);

printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB());

return 0;
}

考虑到数据的封装性,可以将成员变量a和b设置为private属性。
编译运行正常:
c++中的操作符重载

  在c++中,通过对象调用成员函数时,不要忘记还有this指针这一说(this指针可以看文章http://blog.csdn.net/qq_29344757/article/details/76427588),this指针会指向对象的自身,所以对于Add()成员函数,我们可以只传递一个ComplexNumber对象即可:

class ComplexNumber
{
//...

ComplexNumber Add(ComplexNumber& c) //this指针会传来一个ComplexNumber对象,作为加数之一
{
ComplexNumber ret(this->a + c.a, this->b + c.b);
return (ret);
}

//...
};

int main(void)
{
//...

ComplexNumber c3 = c1.Add(c2);

printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB());
}

其运行结果和前面一样。

  成员函数Add()实现了两个复数对象的相加问题,但是c++中操作符重载特性的存在,可以让“+”支持两个复数相加,也就是让两个自定义的类类型相加。如何实现?

先看操作符重载的基本语法:

Type operator sym(const Type& c1, const Type& c2)
{
Type ret;

//...

return ret;
}

  注意,operator为关键字,sym为已定义的操作符,如+,-,*,/,%,>>等等。
  通过operator定义的函数,可以为已定义的操作符拥有新的操作。稍微修改下前面的Add()函数即可:

class ComplexNumber
{
private:
int a; //实部
int b; //虚部

public:
ComplexNumber(int a, int b)
{
this->a = a;
this->b = b;
}

ComplexNumber operator+ (ComplexNumber& c)
{
ComplexNumber ret(this->a + c.a, this->b + c.b);
return (ret);
}

int getA()
{
return a;
}

int getB()
{
return b;
}
};

int main(void)
{
ComplexNumber c1(1, 2);
ComplexNumber c2(5, 9);
ComplexNumber c3 = c1.operator+(c2); //调用c1的operator+()成员函数

//ComplexNumber c3 = c1.Add(c2);

printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB());

return 0;
}

编译运行:
c++中的操作符重载

这样对operator+()函数调用跟调用Add()没啥两样区别,那要是这样呢?

ComplexNumber c3 = c1 + c2;

  这样岂不是实现了两个对象直接调用“+”执行相加操作了么。c++操作符重载的强大之处在于,直接通过“+”符号,编译器会自动检索到operatorr+()函数,且能够正确匹配“+”两边的操作数。

  c++中函数重载的意义就在于扩展函数的功能,使得相同的函数名可以有其它功能,调用的时候,根据上下文(实质就是根据函数参数)调用对应的功能的函数。

  操作符重载也是类似的概念,其本质是通过函数来扩展操作符的功能,这个函数是以operator关键字加上操作符来声明定义的,如上的ComplexNumber operator+ (ComplexNumber& c)。在使用已被重载的操作符来实现对应操作时,如使用“+”实现加法操作,程序如何知道是要使用操作符的重载函数呢?也是根据上下文决定的,这个特性跟前面函数重载根据函数参数调用相对应功能函数一样。另外,全局函数和成员函数都可以实现对操作符的重载,它们最为关键的区别在于,类的成员函数,具有this指针,所以可以少一个操作数,而全局函数没有,所以需要两个操作数。

  复数类的操作不仅仅有+,还有-,*,/,=,==和!=等,依照这个例子就不难实现了。