运算符重载,友元函数与转换函数,这三个其实可以放在一块讲
Java 是没有运算符重载的,呃,也可以说有吧,可以认为部分实现了。
对于基本的 + - * /
,它们不仅可以作用于基本的数据类型,通过运算符重载,定义一个自定义的数据类型(比如结构体)作为参数,可以为它们赋予额外的功能。
格式如下:
operatorop(args)
比如说有如下的结构体:
struct Student
{
private:
int age;
string name;
public:
Student(int age, string name):age(age),name(name){};
Student operator+(Student& anoStu);
void printStudent();
};
对这个结构体,我们重载了加法,让它返回两个 Student 的年龄之和,而名字还是用第一个的:
Student Student::operator+(Student& anoStu)
{
this->age = this->age + anoStu.age;
return *this;
};
这样,如下的函数就可以编译通过了:
Student wenZhi{18,"Wenzhi"};
Student moXiaoju = Student(18, "MoXiaoju");
Student doubleStu = wenZhi + moXiaoju;
不过,重载后的运算符本质也是结构体的一个方法,所以如果你不嫌麻烦,这么写也是可以的:
Student doubleStu2 = wenZhi.operator+(moXiaoju);
注意到我为 Student 编写了一个打印的方法,它的实现如下:
void Student::printStudent()
{
cout << "age = " << this->age << ",name = " << this->name;
}
事实上 <<
,也就是 iostream 的输出符号也是可以重载的(莫不如说它本身就是移位运算符的重载),因此,我们可以声明如下函数:
void operator<<(ostream& os) const;
ostream 的重载要求至少传入一个 ostream 对象;
实现的话,和上面的打印一样:
void Student::operator<<(ostream& os) const
{
os << "age = " << this->age << ",name = " << this->name;
}
但调用就很古怪了,因为重载后的 << 是 Student 的成员函数,所以只能这么用:
doubleStu << cout;
我们需要友元函数,帮我们解决这个问题。友元函数在类(结构体。这里不区分这两种数据结构在 C++ 中的细微差别)中声明,但却不是类的成员函数,却也能访问类的私有成员。一种友元重载声明如下:
friend void operator<<(ostream& os, Student& stu);
实现同上:
void operator<<(ostream& os, Student& stu)
{
os << "age = " << stu.age << ",name = " << stu.name;
}
注意到几点:
这样下面的代码就编译通过了:
cout << doubleStu;
哦对了,如果你想输出多个 Student,最好把返回值改成 ostream
,方便调用。
如下的代码是编译不过的:
Student classMembers = wenZhi + 18;
解决这个问题的方法有很多种,
第一,你可以重载加法,接受 int
或者其他能把 18
转换过来的参数;
第二,由于 C++ 11 的类构造原则得到了改进,我们可以编写只有一个参数的构造函数,我们已经有了一个重载的加法,这样,这个表达式会被视为两个 Student 相加:
Student(int age)
{
this->age = age;
this->name = "Student";
}
对了,我们重载的加法,参数是左值引用,这里应该去掉引用,因为构造函数转换出来的是右值。
第三,我们可以通过转换函数,将类转换成基本类型(某种意义上,这是对系统内置转换函数的“重载”)
operator int();
转换函数必须是类方法,而且不能指定返回类型(方法名已经是返回类型了),且不能有参数。一个实现如下:
Student::operator int()
{
return age;
}
这样表达式就编译通过了吗?没有。由于没有恰当的方法将 int 转成 Student,这表达式还是不通过的。
如果我们将第二步的构造函数也加入类中呢?
main.cpp: In function 'int main()':
main.cpp:40:35: error: ambiguous overload for 'operator+' (operand types are 'Student' and 'int')
40 | Student classMembers = wenZhi + 18;
| ~~~~~~ ^ ~~
| | |
| Student int
main.cpp:40:35: note: candidate: 'operator+(int, int)' <built-in>
40 | Student classMembers = wenZhi + 18;
| ~~~~~~~^~~~
main.cpp:4:9: note: candidate: 'Student Student::operator+(Student)'
4 | Student Student::operator+(Student anoStu)
|
出现了二义性错误,这很好理解,编译器既可以将第一个参数 wenZhi 转成 int,执行两个 int 相加,并将结果转成 Student;也可以将 18 转成 Student,将两个 Student 相加,结果依然是 Student。由于转换函数和加法都是我们定义的,编译器不想承担选择的责任,因此就出现了二义性错误。