【C++】运算符重载,友元函数与转换函数

运算符重载,友元函数与转换函数,这三个其实可以放在一块讲

运算符重载

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;
}

注意到几点:

  1. 声明前加 friend,但定义却不需要加。
  2. 并非类的成员函数,所以不需要类的限定符。
  3. 由于无法获得 this 指针,所以需要传入 Student 对象。

这样下面的代码就编译通过了:

cout << doubleStu;

哦对了,如果你想输出多个 Student,最好把返回值改成 ostream,方便调用。

转换函数

如下的代码是编译不过的:

Student classMembers = wenZhi + 18;

【C++】运算符重载,友元函数与转换函数_第1张图片
解决这个问题的方法有很多种,
第一,你可以重载加法,接受 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。由于转换函数和加法都是我们定义的,编译器不想承担选择的责任,因此就出现了二义性错误。
模棱两可

你可能感兴趣的:(C++,工作业务,c++)