探寻C++类 —— 重载赋值操作符 (operator=)

已经忙碌一个多月,现在才想起来要更博了。今天在写课堂实验时,一题为:

编写一个程序:输入几个学生的姓名、英语和计算机成绩,然后按照总分从高到低排序。要求定义一个Student类,并用友元函数实现排序。

开始看到这题觉得还是挺简单的,其中排序是常见的冒泡排序。众所周知,冒泡排序中,需要建立一个缓存变量来交换变量。而在此例中,需要交换的是类对象,那么解决方法则有两种:

第一种方法是使用一个自定义的equal函数

void equal(Student &a,Student &b)
{
    strcpy(a.name,b.name);  // require include <string>
    a. englishScore = b. englishScore;
    a. computerScore = b. computerScore;
    a. totalScore = b. totalScore;
}

第二种方法则是使用运算符重载,这里则需要重载赋值操作符(operator=)

刚使用重载赋值操作符时,在函数中创建新对象,处理完后返回新对象的引用,结果发现这样做是十分危险而且是错误的。

查阅CSDN和书籍,对于赋值操作符=的重载有如下说明:

string& operator=(const string&);// s1=s2
string& operator=(const char *);// s1="str"
string& operator=(char);// s1='c'

需要注意的是:无论形参为何种类型,赋值操作符必须定义为成员函数,且必须返回对*this的引用。

因而得到以下函数体:

MyClass& MyClass::operator=(const MyClass &T)
{
    // do something
}

但上述函数体仍不完善,例如a=a时会出现什么情况?还有需要考虑性能问题。

为了防止自身赋值,需要判断一下:

MyClass& MyClass::operator=(const MyClass &T)
{
    if (this == &T)
        return *this;
    // do something
    return *this;
}

结合题目,可写出如下重载函数:

Student& Student::operator=(const Student &T)
{
    if (this == &T)
        return *this;
     
    strcpy(name, T.name);   // require include <string>
    englishScore = T.englishScore;
    computerScore = T.computerScore;
    totalScore = T.totalScore;
    return *this;
}

通过实验,发现使用重载操作符会比使用equal函数更方便,从而整理出重载操作符的一些规则供以后学习使用。

  1. 除了函数调用操作符之外,重载操作符的形参数目(包括成员函数的隐式this指针)与操作符的操作数数目相同。
  2. 形参值要为const类型。
  3. 返回一个引用,以便于实现a=b=c。
  4. &&、&、||和,等操作符最好不要重载。
  5. 类一般都需重载输入/输出操作数,IO操作符必须为非成员符,所以类常将其设为友元。
  6. 作为成员函数的操作符有一个隐含的this形参,限定为第一个操作数。
  7. 重载操作符必须具有至少一个类类型的操作数。