欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

运算符重载

程序员文章站 2022-05-18 16:48:50
...

    运算符重载: 当运算符作用于类类型的运算对象时, 可以通过运算符重载重新定义该运算符的含义。

    重载的运算符是具有特殊名字的函数: 它们由关键字operator和其后要定义的运算符号共同组成。

    和其他函数一样,重载的运算符也包含返回类型、参数列表以及函数体。

    运算符重载的定义:

返回类型 operator运算符号(形参列表)
{
       函数体
}

    其中, operator运算符号为函数名, 比如运算符+的重载的函数名为 operator+

Count operator+(const Count &c); //为成员函数
friend Count operator+(const Count &c1, const Count &c2);//为友
元函数

注意:

  • 重载运算符函数的参数数量与该运算符作用的运算对象一样多。
  • 如果一个运算符重载函数是成员函数, 则它的左侧运算对象绑定到隐式的this指针上。 因此, 成员运算符函数的显式参数数量比运算对象的总数少一个。
  • 对于一个运算符函数来说, 它或者是类的成员, 或者至少含有一个类类型的参数。

运算符重载函数的实现:

  • 成员函数的实现:
  • 友元函数的实现:

运算符重载函数的调用:

  • 通过运算符+来计算和
total = c1 + c2;
  • 通过调用函数的方式来计算和
total = c1.operator+(c2); //为成员函数
total = operator+(c1, c2); //为友元函数

运算符重载的规则

运算符重载

运算符重载

重载运算符时需注意:

  • 不改变运算符的优先级
  • 不改变运算符的结合性
  • 不改变运算符所需要的操作数
  • 不能创建新的运算符

    用成员函数或友元函数重载运算符的区别,在于成员函数具有this指针, 而友元函数没有this指针。

  • 一元运算符:
Object op 或 op Object //op代指运算符
1.重载为成员函数时, 调用方式:
Object.operator op(); //通过this指针隐式传递
2.重载为友元函数时, 调用方式:
operator op(Object); //通过参数Object显式传递
  • 二元运算符:
ObjectL op ObjectR
1.重载为成员函数时, 调用方式:
ObjectL.operator op(ObjectR); //左操作数通过this指针隐式
传递, 右操作数由参数ObjectR显式传递
2.重载为友元函数时, 调用方式:
operator op(ObjectL, ObjectR); //左右操作数都通过参数显
式传递

运算符重载的实例1

    ++(自增运算符)、 –(自减运算符)

1.前置 ++Object/--Object
Count& operator++(); //为成员函数
friend Count& operator++(Count &c1); //为友元函数
2.后置 Object++/Object--
Count operator--(int); //为成员函数
friend Count operator--(Count &c1, int); //为友元函数

    注意: C++中通过一个占位参数(int)来区别前置运算和后置运算。

    ++(自增运算符)重载函数的实现:

     1. 前置++(先自增再使用)

     2. 后置++(先使用再自增)

运算符重载的实例2

    =(赋值运算符)

1.Time t1 = t2; //有新的对象实例产生(t1), 调用拷贝构造函数。
Time(const Time& t);
2.t1 = t2 = t3; //没有新的对象实例产生, 调用重载的赋值运算符。
Time& operator=(const Time& t);

    注意:
    当程序没有显式地提供一个以本类或本类的引用为参数的赋值运算符重载函数时, 编译器会自动生成这样的一个赋值运算符重载函数和拷贝构造函数。

    拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。

    如果一个类不包含指针, 则不需要自定义赋值操作符与拷贝构造函数。 编译器会给每个类创建一个默认的拷贝构造函数和默认的赋值操作符。 但是, 当类中包含有指针或任何运行时分配的资源时, 编译器生成的这两个函数, 可能会失效。 这时就需要我们自定义赋值操作符与拷贝构造函数了。

    =(赋值运算符)重载函数的实现:

     1.赋值运算符重载函数的实现:

     2.拷贝构造函数的实现:

运算符重载的实例3

    +=、 -=、 *=、 /=、 %=(复合的赋值运算符)

t1 += t2; //相当于 t1 = t1 + t2。
Time& operator+=(Time &t);

     注意:

     1.复合的赋值运算符具有给运算对象重新赋值的功能, 所以需要返回引用类型, 返回*this。

     2.+=运算符的行为应与其内置版本一致, 即先执行+, 再执行=。

     +=(复合赋值运算符)重载函数的实现:

运算符重载的实例4

    <<(输出运算符)、 >>(输入运算符)

    1.<<(输出运算符)

cout << t1;
friend ostream &operator<<(ostream &os,const Time &t); //os << t

    注意:
    需要为友元函数, 因为需要返回ostream对象, 如果是成员函数的话, 返回的就是该类的类对象。

    输出运算符的第一个形参是一个非常量ostream对象的引用, 非常量是因为向流写入内容会改变其状态; 使用引用是因为我们无法直接复制一个os对象。

    第二个形参一般是一个常量的引用, 该常量是我们想要打印的对象。

    <<(输出运算符)重载函数的实现:

    2.>>(输入运算符)

cin>> t1;
friend istream &operator>>(istream &is , Time &t); //is >> t

    注意:
    这里返回的是istream对象, 第一个参数也是一个istream对象的引用。

    第二个形参不能是常量, 因为我们要修改它里面存储的值。

    输入运算符必须处理可能失败的情况, 如果输入失败, 则调用默认构造函数。

    >>(输入运算符)重载函数的实现:

运算符重载的实例5

    ==(相等运算符)重载函数的实现:

运算符重载的实例6

    ()(函数调用运算符)

t1 = t1();
Time& operator()(); //这里的函数调用运算符, 负责将对象的
minutes_转换为060之间的数。

    注意:

    如果类重载了函数调用运算符, 则我们可以像使用函数一样使用该类。

    函数调用运算符必须是成员函数。

    一个类可以定义多个不同版本的调用运算符, 相互之间应该在参数数量或类型上有所不同。

    ()(函数调用运算符)重载函数的实现:

运算符重载的实例7

    &&(逻辑与运算符)、 ||(逻辑或运算符)

     注意: 不要重载&&和||运算符。

    &&和||是C++中非常特殊的操作符, 它们实现了短路求值属性。

(2 > 3) && (3 == 3)$; //首先求得(2 > 3)的值, 并判断是否为true,这里为false, 则整个表达式的结果为false, (3==3) 不会被求值。

    运算符重载是靠函数重载来完成的, 所以使用重载的运算符本质上是一次函数调用, 所以运算对象总是会被求值。 无法保留短路求值属性。