C++重载操作符


操作符重载

包括 +,-,/,% 等在内的(二元)操作符本质上是函数。调用这种“函数”时,要以不同的语法列出实参。操作符函数的实参要在操作符前后列出;普通函数的实参则在函数名之后的圆括号中列出。操作符函数的定义与普通函数相似,只是要在操作符之前附加保留字 operator。可为类类型重载预定义操作符(比如+),为这些操作符赋予新含义。

虽然并非必须,但操作符可作为类的友元。下面的示例代码展示如何将操作符 +,==重载为友元。

#include <iostream>

using namespace std;

class Example
{
public:
    friend Example operator +(const Example& ex1, const Example& ex2);
    friend bool operator ==(const Example& ex1, const Example& ex2);

    int get_a();
    int get_b();

    Example(int _a, int _b);
    Example();

private:
    int a,b;
};
int main()
{
    Example ex1(1, 2), ex2(3, 4);
    Example ex3 = ex1 + ex2;
    cout<<ex3.get_a()<<" "<<ex3.get_b()<<endl; // 4 6
    if(ex1 == ex2)
        cout<<"ex1 is equal to ex2"<<endl;
    else
        cout<<"ex1 is not equal to ex2"<<endl;
    return 0;
}

Example operator + (const Example& ex1, const Example& ex2)
{
    Example res;
    res.a = ex1.a + ex2.a;
    res.b = ex1.b + ex2.b;
    return res;
}

bool operator == (const Example& ex1, const Example& ex2)
{
    if(ex1.a == ex2.a && ex1.b == ex2.b)
        return true;
    else
        return false;
}

Example::Example() : a(0), b(0)
{

}

Example::Example(int _a, int _b) : a(_a), b(_b)
{

}

int Example::get_a()
{
    return a;
}

int Example::get_b()
{
    return b;
}

大多数(但并非全部)操作符都可重载。操作符不一定是类的友元,但一般情况下都希望如此。具体的操作符重载规则如下:

  • 重载操作符时,至少一个实参必须是类类型。
  • 重载的操作符可以是(但不一定是)类的友元;操作符函数可以是类的成员,也可以是普通(非友元)函数。
  • 不能新建操作符。只能重载现有操作符,比如 +,-,*,/,% 等。
  • 不能改变操作符获取的实参数量。例如,重载 % 时,不能把它从二元操作符变成一元操作符;重载 ++ 时,不能把它从一元操作符变成二元操作符。
  • 不能改变操作符的优先级。重载的操作符具有和原始版本一样的优先级。例如,x * y + z 总是表示 (x * y) + z,即使 xyz 是对象,而且操作符 +* 已针对相应的类进行了重载。
  • 以下操作符不可重载:圆点操作符(.)、作用域解析操作符(::)以及.*?

这里需要重点说明的是,将操作符函数作为类的成员与友元函数的区别。下面以操作符函数作为类的成员重现上面的示例代码:

#include <iostream>

using namespace std;

class Example
{
public:
    Example operator +(const Example& ex2);
    bool operator ==(const Example& ex2);

    int get_a();
    int get_b();

    Example(int _a, int _b);
    Example();

private:
    int a,b;
};
int main()
{
    Example ex1(1, 2), ex2(3, 4);
    Example ex3 = ex1 + ex2;
    cout<<ex3.get_a()<<" "<<ex3.get_b()<<endl; // 4 6
    if(ex1 == ex2)
        cout<<"ex1 is equal to ex2"<<endl;
    else
        cout<<"ex1 is not equal to ex2"<<endl;
    return 0;
}

Example Example::operator + (const Example& ex2)
{
    Example res;
    res.a = a + ex2.a;
    res.b = b + ex2.b;
    return res;
}

bool Example::operator == (const Example& ex2)
{
    if(a == ex2.a && b == ex2.b)
        return true;
    else
        return false;
}

Example::Example() : a(0), b(0)
{

}

Example::Example(int _a, int _b) : a(_a), b(_b)
{

}

int Example::get_a()
{
    return a;
}

int Example::get_b()
{
    return b;
}

作为类的成员,函数声明定义时就只需要包含一个参数即可,ex1+ex2 相当于 ex1 作为对象调用其成员函数 + 获取参数 ex2。因为是类的成员,所以其函数定义时,获取 ex1.a 就直接使用 a 就可以。

除了写法上的区别,作为类的成员,其只能位于第一个参数的位置(作为调用对象),比如下面的一个例子。无论是作为类的成员还是友元函数都是合法的。

Example ex1(2,1), ex2;
ex2 = ex1 + 20;

而下面的例子,如果作为类的成员就是不合法的,而作为友元函数则合法。

Example ex1(2,1), ex2;
ex2 = 20 + ex1;

用于自动类型转换的构造函数

如果类定义包含了恰当的构造函数,系统会自动执行特定的类型转换。例如下面的示例:

Example ex1(2,1), ex2;
ex2 = ex1 + 20;

代码看起来简单和自然,但存在一个问题,就是我们之前的代码没有重载对象与整型之间的 + 操作,而只是重载了对象之间的 + 操作。

有两个方法解决这个问题,一个很单纯地方法就是重载一个对象与整型之间的 + 操作,另一个方法就是利用构造函数。我们可以按照下面的方式定义一个获取一个整型的构造函数。

Example(int _a) : a(_a), b(0) {}

这样代码在发现没有进行对象和整型之间的 + 重载,会自动执行这个构造函数,生成一个匿名对象。


重载一元操作符

当然除了重载二元操作符(+,-,==等),还可以重载一元操作符,比如求反操作符 -,递增操作符 ++,递减操作符 -- 等。下面用代码简单说明如何重载求反操作符。

#include <iostream>

using namespace std;

class Example
{
public:
//    friend Example operator +(const Example& ex1, const Example& ex2);
//    friend bool operator ==(const Example& ex1, const Example& ex2);

    Example operator +(const Example& ex2);
    bool operator ==(const Example& ex2);

    friend Example operator -(const Example& ex);

    int get_a();
    int get_b();

    Example(int _a, int _b);
    Example();

private:
    int a,b;
};
int main()
{
    Example ex1(1, 2), ex2(3, 4);
    Example ex3 = ex1 + ex2;
    cout<<ex3.get_a()<<" "<<ex3.get_b()<<endl; // 4 6
    if(ex1 == ex2)
        cout<<"ex1 is equal to ex2"<<endl;
    else
        cout<<"ex1 is not equal to ex2"<<endl;
    Example ex4 = -ex1;
    cout<<"ex4 is opposite to ex1, it is "<<ex4.get_a()<<" "<<ex4.get_b()<<endl; // -1 -2
    return 0;
}

Example Example::operator + (const Example& ex2)
{
    Example res;
    res.a = a + ex2.a;
    res.b = b + ex2.b;
    return res;
}

bool Example::operator == (const Example& ex2)
{
    if(a == ex2.a && b == ex2.b)
        return true;
    else
        return false;
}

Example operator - (const Example& ex)
{
    Example res;
    res.a = -ex.a;
    res.b = -ex.b;
    return res;
}

Example::Example() : a(0), b(0)
{

}

Example::Example(int _a, int _b) : a(_a), b(_b)
{

}

int Example::get_a()
{
    return a;
}

int Example::get_b()
{
    return b;
}


重载>>和<<

cout 使用的插入操作符 << 是二元操作符。例如以下语句:

cout << "Hello out there.\n" ;

操作符是 <<,第一个操作数是输出流 cout,第二个则是字符串值 "Hello out there.\n"。这两个操作数都可以改变。如 foutofstream 类型的输出流,而且已通过 open 调用与一个文件连接,就可将 cout 替换成 fout,字符串会写到与 fout 连接的文件中。当然,还可以将字符串 "Hello out there.\n" 替换成其他字符串、变量或数字。由于 << 是操作符,所以应该能像重载 +- 等操作符那样重载 <<,但是需要注意更多细节。

  1. 返回值必须是流。
  2. 返回值类型名称后必须添加符号 &
// 函数声明
class ClassName
{
public:
	friend istream& operator >>(istream& Parameter_1,
								ClassName& Parameter_2);
	friend ostream& operator <<(ostream& Parameter_3,
								const ClassName& Parameter_4);

// 定义
istream& operator >>(istream& Parameter_1,
					 ClassName& Parameter_2)
{

}
ostream& operator <<(ostream& Parameter_3,
					const ClassName& Parameter_4)
{

}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值