一、概念
  • 对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
  • 重载的运算符是具有特殊名字的函数,该函数也有返回值、参数列表、函数体
二、运算符重载的3种实现方式
  • 成员函数:私有、公有、保护都可以
  • 友元函数:同上
  • 全局函数:只能访问公有的
三、运算符重载的规则

C++:12---运算符重载(operator)_初始化

  • 以下运算符不支持重载:.(类属运算符),::(作用域运算符),sizeof,?:(三目运算符),#(预处理运算符)
  • 只能用成员函数重载的运算符:=(赋值运算符)、()(强制类型转换)、[]、new、delete、->
  • 只能用友元、全局函数重载的运算符:<<、>>
  • +=、-=、=运算符返回值为引用类型(&):函数执行完之后返回的是*this(对象本身)。如果不加&,则返回的是临时对象
  • 承接上一注意事项:前置++、--,返回值为引用。后置++、--,返回值不为引用
四、+、-、*、/、+=、-=的重载
  • //只实现+、*,+=。其它原理都相同
class Cperson
{
private:
    int data;
public:
    Cperson operator+(Cperson const& other)const;//类成员函数实现
    friend Cperson operator*(Cperson const& p1,Cperson const& p2);//友元函数方式实现
    Cperson& operator+=(Cperson const& other);
};
Cperson Cperson::operator+(Cperson const& other)const
{
    Cperson temp;
    temp.data=this->data+other.data;
    return temp;
}
Cperson operator*(Cperson const& p1,Cperson const& p2)
{
    Cperson temp;
    temp.data=p1.data*p2.data;
    return temp;
}
Cperson& Cperson::operator+=(Cperson const& other)
{
    Cperson temp=*this=other;//因为前面已经实现了+运算符,此处直接使用
    return *this=temp;
}
五、 赋值运算符(=)的重载
  • 赋值运算符的重载,返回值应该为运算符左侧对象的一个引用,否则返回的是一个临时对象
  • 如果没有写赋值重载运算符,编译器自动存在一个默认的,就是拷贝构造中所用到的默认拷贝构造,但是如果类成员变量中含有动态内存的变量时,需要重载赋值运算符
class Cperson
{
private:
    char* name;
public:
    Cperson& operator=(Cperson const& other);
};
Cperson& Cperson::operator=(Cperson const& other)
{
    if(this->name)//先释放原先的数据
        delete[] name;
    if(other)//如果传入的参数不为空
    {
        int len=strlen(other.name);
        this->name=new char[len+1];
        strcpy(this->name,other.name);
    }
    else//如果传入的参数为空
    {
        other.name=nullptr;
    }
};

拷贝构造函数与拷贝赋值运算符的关系

  • 拷贝构造函数是用另一个对象来初始化一块内存区域这块内存就是新对象的内存区
  • 赋值函数是对于一个已经被初始化的对象来进行operator=操作。例如:
class A;

A a;

A b = a; // 调用拷贝构造函数, 因为b是第一次初始化
A c(a);  // 调用拷贝构造函数, 因为c是第一次初始化

b = c;   // 调用赋值运算符, 因为b已经初始化过了
六、 ++、--运算符的重载
  • 为了区别前置和后置:后置++的参数为int,前置++无参数
  • 前置++、--,返回值为引用。后置++、--,返回值不为引用
  • ++、--(前置后置),下面只演示++的操作
class Cperson
{
private:
    int data;
public:
    Cperson& operator++();//前置++,返回值为引用
    Cperson operator++(int);//后置++,返回值不为引用
};
Cperson& Cperson::operator++()
{
    data++;
    return *this;
}
Cperson Cperson::operator++(int)
{
    Cperson temp=*this;
    data++;
    return temp;
}
七、==、!=运算符的重载
  • 用途:这两个运算符用来判断两个类对象中数据成员的值是否相等/不相等(可以在重载中判断单/多个成员是否相等)

设计规则:

  • 通常情况下,==运算符应该具有传递性,例如:如果a==b和b==c,那么a==c应该也为真
  • 如果实现了==运算符,则!=运算符可以直接在return语句中应用刚才实现的==运算符来简化书写
  • 如果用成员函数实现只能有一个参数,用友元、全局函数实现是两个参数
class Cperson
{
private:
    int id;
    int age;
public:
    Cperson(int Id, int Age) :id(Id), age(Age) {}
    int getId()const;
    int getAge()const;
    friend bool operator==(const Cperson &p1, const Cperson &p2)
    {
        return ((p1.getId() == p2.getId()) && (p1.getAge() == p2.getAge()));
    }

    friend bool operator!=(const Cperson &p1, const Cperson &p2)
    {
        return !(p1 == p2);
    }
};

int Cperson::getId()const { return id; }
int Cperson::getAge()const { return age; }
八、 >>、<<运算符的重载
  • 输入输出运算符的重载不能用成员函数实现,一般用友元实现

重载输出运算符<<

参数:

  • 参数1:一个非常量ostream对象的引用(ostream是非常量是因为向流写入内容会改变其状态)
  • 参数2:一般来说是一个常量的引用,该常量是我们想要打印的类类型(使用引用的原因是我们希望避免复制实参。使用常量是因为不会改变对象的内容)

返回值:返回它的ostream形参

重载输入运算符>>

参数:

  • 参数1:是运算符将要读取的流的引用
  • 参数2:将要读入到的(非常量)的引用(使用非常量是因为输入运算符本身的目的就是将数据读入到这个对象中)

返回值:某个给定流的引用

输入时可能产生的错误:

  • 输入的类型不符
  • 当读取操作达到文件末尾或者遇到输入流的其它错误时也会失败
class Cpoint
{
private:
    int x;
    int y;
public:
    friend ostream& operator<<(ostream& os, const CMyPoint const& pt);//输出流
    friend istream& operator>>(ostream& is, const CMyPoint const& pt);//输入流
}
ostream& operator<<(ostream& os, const CMyPoint const& pt)
{
    os<<pt.x<<pt.y;
    return os;
}
istream& operator>>(ostream& is,const CMyPoint const& pt)
{
    is>>pt.x>>pt.y;
    return is;
}
九、[]下标运算符的重载

待续

十、*、->成员访问运算符的重载

待续

十一、()函数调用运算符的重载
  • 如果类重载了函数调用运算符,那么我们在使用该对象时就如同调用一个函数一样
  • 注意:()运算符与对象初始化时调用构造函数不是一个东西、因此()函数调用运算符不能再类初始化时使用,会与构造函数冲突
struct absInt {
    bool operator()(int value) {
        return value < 0 ? true : false;
    }
};
int main()
{
    absInt a;
    printf("%d\n", a(-1));//打印1
    return 0;
}