C++运算符的重载

C++运算符的重载

什么是运算符的重载

简而言之,就是将运算符定义成一种函数,简化我们的调用。函数的定义类似这种形式 Type operator+(参数列表);

不同运算符的重载

1. 一般的二元运算符

类似于 "+" “-” “*” "/" 的重载实现方式如下 (以下以“ +”的重载为例 )

//我们先定义一个类Complex,以实现复数之间的计算
class Complex
{
    public:
    	Complex()//无参构造函数
        {
            real = imaginary = 0;
        }
    	Complex(int real, int imaginary)//有参构造函数
        {
            this->real = real;
            this->imaginary = imaginary;
        }
    	string toString() const
        {
            stringstream ss; //要使用stringstream需要包含 ssstream 头文件
            if(real != 0) ss << real;
            if(imaginary > 0) ss << " + " << imaginary << "i";
            else if(imaginary < 0) ss << " - " << abs(imaginary) << "i"; //要使用abs()函数需要包含 cstdlib 头文件
        }
    	Complex add(const Complex& secondComplex) const; //实现复数的加法(学习了重载之前)
    	Complex operator+(const Complex& secondComplex) const;//实现复数的加法(学习了重载之后)
    private:
    	int real;//实部
    	int imaginary;//虚部
};

接下来是对复数加法函数的定义。

Complex Complex::add(const Complex& secondComplex) const //函数末尾的const意为此函数为常成员函数,即不能改变成员变量值的函数
{
	return Complex(real + secondComplex.real, imaginary + secondComplex.imaginary);
}
Complex Complex::operator+(const Complex& secondComlex) const
{
    return Complex(real + secondComplex.real, imaginary + secondComplex.imaginary);
}

两个函数的内容完全一样,唯一的区别就在于函数头。对于运算符重载函数的调用有两种方式如下:

Complex r1(1, 1), r2(2, 2);//先定义两个Complex类的变量
Complex r3, r4;
r3 = r1.operator+(r2);//调用方法一
r4 = r1 + r2;//调用方法二

调用方法一形式与普通函数的调用方法一致。对于第二种调用方法才能提现出运算符重载的精妙之处,看起来更顺眼了。

接下来来验证输出是否有正确。

Complex r5;
r5 = r1.add(r2);//增加一组老朋友
cout << "老朋友: " << r5.toString() << endl;
cout << "调用方法一结果: " << r3.toString() << endl;
cout << "调用方法二结果: " << r4.toString() << endl;

输出如下

avatar

可以看出结果完全一样,符合预期。

2. 重载 [ ] 运算符

对于数组下标运算符 “[ ]” 既可以用于访问对象,也可以用来修改对象。下面来介绍"[ ]"的重载。

如果按照上述的思路,写出来的代码会像下面这样:

注意要在class Complex中声明[ ]重载函数。

//继续沿用上个例子的Complex类
int Complex::operator[](int index) //别忘记声明!!!
{
    if(index == 0) return real;
    else return imaginary;
}

运行以下代码:

Complex r6(1,3);
cout << "实部是 " << r6[0] << " 虚部是 " << r6[1] << endl;

得到:

avatar

看起来结果没有什么问题,但是如果执行以下语句就会出现编译错误

r6[0] = 2;
r6[1] = 3;

avatar

那我们该怎么解决这个问题呢?__办法就是将[ ]运算符函数声明为一个引用。__这样是不是就可以实现赋值和访问了呢。

修改后的[ ]重载函数

int& Complex::operator[](int index) //别忘记修改class内容使形式对应
{
    if(index == 0) return real;
    else return imaginary;
}

重新运行

Complex r6(1, 3);
cout << "实部是 " << r6[0] << " 虚部是 " << r6[1] << endl;
r6[0] = 2;
r6[1] = 3;
cout << "实部是 " << r6[0] << " 虚部是 " << r6[1] << endl;

avatar

结果正确。

小总结:将函数声明为一个引用,即函数会返回一个变量的”别名“。修改别名也就相当于修改其本身。

3. 重载简写运算符

对于像 =="+=" “-=” “*=” “/=” 和 “%=“这类的简写运算符,思路跟”[ ]”==类似。下面直接给出代码。

Complex& Complex::operator+=(const Complex& secondComplex)
{
    *this = add(secondComplex);
    return *this;
}

必须要返回一个引用的原因在于:简写运算符可以作为左值(即被赋值的值)使用,例如:

int x = 0;
(x += 2) += 3;

如果返回值不是引用,那么这两句代码执行后x的值为2。返回引用是为了使该函数可以作为左值。

4. 重载一元运算符

类似于正负数,负数前会有一个 " - " 。我们同样可以对其进行重载。下面给出代码:

Complex Complex::operator-()
{
    return Complex(-real, -imaginary);
}

由于在数前加上符号并不会改变数的值,所以该函数无需返回引用。例如:a = 1 -a = -1 但 a = 1 不受影响。

5. 重载 ++ 和 – 运算符

自增、自减有一个不同于其他运算符的特点就是运算符所处的位置不同,带来的结果也不同。那么如何让C++分辨出此类运算符的位置的呢?我们需要使用int型的伪参数。实现代码如下:

//下面把复数的自增定义为实数和虚数各加一
//Prefix increment
Complex& Complex::operator++()
{
    real++;
    imaginary++;
    return *this;
}
//Postfix increment
Complex Complex::operator++(int dummy)
{
    Complex tmp(real, imaginary);
    real++;
    imaginary++;
    return tmp;//返回值为自增前的值
}

其中为什么前自增需要返回一个引用而后自增不需要显而易见,因为前自增这个式子的值是他本身的值,即(a++) 的值就是a现在的值。

6. 重载 << 和 >> 运算符

在此之前我们都是需要通过 toString() 来将输出结果转化为字符串,然后以字符串形式输出,那么我们是否可以直接使用 cout << Complex 进行输出呢?

答案显然是肯定的,但需要引入友元函数的概念。

(1) 友元函数

用自己的话说,友元函数即是在一个类A中声明一个属于别处的函数,然后在别处通过这个函数可以访问类A的private成员。

声明友元函数的方法也很简单,只需要在一般声明函数的基础上,在头上加上friend

例如:

friend void function1(...);
(2) 重载 << and >>

现在有了友元函数的基础,我们可以进行重载函数的书写。

事实上,流插入运算符( << )和流提取运算符( >> )与普通的二元运算符无异。

cout << variable; <=> <<(cout, variable);

cin >> variable; <=> >>(cin, variable);

对于运算符 << 有两个算子,其中的cout是ostream类中的实例,因此,cout不能作为Complex类的成员函数被重载。>> 同理。下面给出友元函数声明的代码:

friend ostream& operator<<(ostream& out, const Complex& complex);
friend istream& operator>>(istream& in, Complex& complex);//由于要赋值,所以不能加const

接着是函数具体代码:

ostream& operator<<(ostream& out, const Complex& complex)
{
    if(complex.real != 0) out << complex.real;
    if(complex.imaginary > 0) out << " + " << complex.imaginary;
    else if(complex.imaginary < 0) out << " - " << abs(complex.imaginary);
    return out;
}
istream& operator>>(istream& in, Complex& complex)
{
    cout << "Enter Real: ";
    in >> complex.real;
    cout << "Enter Imaginary: ";
    in >> complex.imaginary;
    return in;
}

总结

笔者也是刚开始C++的学习,对于运算符重载这一部分的学习。对于引用友元等方面有了更深的了解。总体而言,难度不是很高。对于其中有几点还是有些没有吃透,比如C++中的 &const的理解还是很浅。对于这些我会尽快学习补漏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值