C++重载操作符

文章目录

  • 操作符重载
  • 用于自动类型转换的构造函数
  • 重载一元操作符
  • 重载>>和<<


操作符重载

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

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

#include 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 6if(ex1 == ex2)cout<<"ex1 is equal to ex2"<<endl;elsecout<<"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;elsereturn 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 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 6if(ex1 == ex2)cout<<"ex1 is equal to ex2"<<endl;elsecout<<"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;elsereturn 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 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 6if(ex1 == ex2)cout<<"ex1 is equal to ex2"<<endl;elsecout<<"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 -2return 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;elsereturn 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)
{}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部