快速认识运算符重载:
class C
{
    int i;
public:
    C(int iTmp);
};
C::C(int iTmp)
{
    i =  iTmp;
}

int _tmain(int argc, _TCHAR* argv[])
{
    C c1(1),c2(2),c3(3);
    //c3 = c1 + c2;//编译不过
    return 0;
}

运算符重载: 

#include "stdafx.h"
#include <iostream>
class C
{
public:
    int i;
    C(int iTmp);
};
C::C(int iTmp)
{
    i =  iTmp;
}
//运算符重载是全局函数
operator+(C c1,C c2)
{
    return C(c1.i + c2.i);
}

int _tmain(int argc, _TCHAR* argv[])
{
    C c1(1),c2(2),c3(0);
    c3 = c1 + c2;//编译通过
    std::cout<<c3.i<<std::endl;
    return 0;
}

参考:C++运算符重载函数基础及其值返回状态
  运算符重载是C++的重要组成部分,它可以让程序更加的简单易懂,简单的运算符使用可以使复杂函数的理解更直观。 
  对于普通对象来说我们很自然的会频繁使用算数运算符让他们参与计算,但是对于自定义类的对象来说,我们是无论如何也不能阻止写出像下面的代码一样的程序来的。 
  例子如下:
class Test  
{  
 //过程省略  
}  

  
int main()  
{  
    Test a,c;  
    c=a+a;  
}

  当然这样的代码是不能够通过编译的,c++对自定类的算术运算部分保留给了程序员,这也是符合c++灵活特性的。

  在c++中要想实现这样的运算就必须自定义运算符重载函数,让它来完整具体工作。

  在这里要提醒读者的是,自定义类的运算符重载函数也是函数,你重载的一切运算符不会因为是你自己定义的就改变其运算的优先级,自定义运算符的运算优先级同样遵循与内部运算符一样的顺序。

C++运算重载

  除此之外,c++也规定了一些运算符不能够自定义重载,例如.、::、.*、.->、?:。

  下面我们来学习如何重载运算符,运算符重载函数的形式是: 

返回类型 operator 运算符符号 (参数说明) 

//函数体的内部实现 


  运算符重载函数的使用主要分为两种形式,一种是作为类的友元函数进行使用另一种则是作为类的成员函数进行使用。 

  下面我们先看一下作为类的友元函数使用的例子:

#include <iostream>  
using namespace std;  
  
class Test  
{  
    public:  
        Test(int a = 0)  
        {  
            Test::a = a;  
        }  
        friend Test operator +(Test&,Test&);  
        friend Test& operator ++(Test&);  
    public:  
        int a;  
};  
Test operator +(Test& temp1,Test& temp2)//+运算符重载函数  
{  
    //cout<<temp1.a<<"|"<<temp2.a<<endl;//在这里可以观察传递过来的引用对象的成员分量  
    Test result(temp1.a+temp2.a);  
    return result;  
}  
Test& operator ++(Test& temp)//++运算符重载函数  
{  
    temp.a++;  
    return temp;  
}  
int main()  
{  
    Test a(100);  
    Test c=a+a;  
    cout<<c.a<<endl;  
    c++;  
    cout<<c.a<<endl;  
    system("pause");  
}

  在例子中,我们对于自定义类Test来说,重载了加运算符与自动递增运算符,重载的运算符完成了同类型对象的加运算和递增运算过程。
  重载运算符函数返回类型和形式参数也是根据需要量进行调整的,下面我们来看一下修改后的加运算符重载函数。 

  代码如下: 

#include <iostream>  
using namespace std;  
  
class Test  
{  
    public:  
        Test(int a = 0)  
        {  
            Test::a = a;  
        }  
        friend Test operator +(Test&,const int&);  
    public:  
        int a;  
};  
Test operator +(Test& temp1,const int& temp2)//+运算符重载函数  
{  
    Test result(temp1.a * temp2);  
    return result;  
}  
int main()  
{  
    Test a(100);  
    Test c = a + 10;  
    cout<<c.a<<endl;  
    system("pause");  
}

  上面修改后的例子中,我们让重载后的加运算符做的事情,事实上并不是同类型对象的加运算,而是自定义类对象与内置int常量对象的乘法运算。 

  值得注意的是,对于运算符重载来说,我们并不一定要用它一定要做同类型对象的加法或者是其它运算,运算符重载函数本身就是函数,那么在函数体内部我们是可以做任何事情的,但是从不违背常规思维的角度来说,我们没有必要让重载加运算的函数来做与其重载的符号意义上完全不相符的工作,所以在使用重载运算符脱离原意之前,必须保证有足够的理由。

  下面我们讨论一下作为类成员函数的运算符重载函数的使用,及其函数的值返回与引用返回的差别。 

  下面我们先看实例,而后逐步分析。 

  代码如下(重要部分做了详细的注解): 

  
#include <iostream>  
using namespace std;  
  
class Test  
{  
    public:  
        Test(int a = 0)  
        {  
            Test::a = a;  
        }  
        Test(Test &temp)  
        //运算符重载函数为值返回的时候会产生临时变量,临时变量与局部变量result的复制会调用拷贝构造函数,临时变量的生命周期是在拷贝构造函数运行完成后才结束,但如果运算符重载函数返回的是引用,那么不会产生临时变量,而局部变量result的生命周期在运算符重载函数退出后立即消失,它的生命周期要比临时变量短,所以当外部对象获取返回值的内存地址所存储的值的时候,获得是一个已经失去效果的内存地址中的值,在这里的值返回与引用返回的对比,证明了临时变量的生命周期比局部变量的生命周期稍长。  
        {  
            cout<<"载入拷贝构造函数"<<"|"<<temp.a<<endl;//注意这里,如果修改运算符重载函数为返回引用,这里就会出现异常,temp.a将获得一个随机值。  
            Test::a = temp.a;  
        }  
        ~Test()//在mian()内析构的过程是result局部变量产生的  
        {  
            cout<<"载入析构函数!"<<endl;  
            cin.get();  
        }  
        Test operator +(Test& temp2)//+运算符重载函数  
        {  
            //cout<<this->a<<endl;  
            Test result(this->a+temp2.a);  
            return result;  
        }  
        Test& operator ++()//++运算符重载函数  
  
        //递增运算符是单目运算符,使用返回引用的运算符重载函数道理就在于它需要改变自身。  
        //在前面我们学习引用的单元中我们知道,返回引用的函数是可以作为左值参与运算的,这一点也符合单目运算符的特点。  
        //如果把该函数改成返回值,而不是返回引用的话就破坏了单目预算改变自身的特点,程序中的++(++c)运算结束后输出c.a,会发现对象c只做了一次递增运算,原因在于,当函数是值返回状态的时候括号内的++c返回的不是c本身而是临时变量,用临时变量参与括号外的++运算,当然c的值也就只改变了一次。  
        {  
            this->a++;  
            return *this;  
        }  
    public:  
        int a;  
};  
  
int main()  
{  
    Test a(100);  
    Test c=a+a;  
    cout<<c.a<<endl;  
    c++;  
    cout<<c.a<<endl;  
    ++c;  
    cout<<c.a<<endl;  
    ++(++c);  
    cout<<c.a<<endl;  
    system("pause");  
}

  上例中运算符重载函数以类的成员函数方式出现,细心的读者会发现加运算和递增运算重载函数少了一个参数,这是为什么呢? 
  因为当运算符重载函数以类成员函数身份出现的时候,C++会隐藏第一个参数,转而取代的是一个this指针。 

接下来我们具体分析一下运算符重载函数的值返回与引用返回的差别。 

  当我们把代码中的加运算重载函数修改成返回引用的时候:

        Test& operator +(Test& temp2)//+运算符重载函数    
        {  
            Test result(this->a+temp2.a);    
            return result;    
        }

  执行运算符重载函数返回引用将不产生临时变量,外部的Test c=a+a; 将获得一个局部的,栈空间内存地址位置上的值,而栈空间的特性告诉我们,当函数退出的时候函数体中局部对象的生命周期随之结束,所以保存在该地址中的数据也将消失,当c对象去获取存储在这个地址中的值的时候,里面的数据已经不存在,导致c获得的是一个随机值,所以作为双目运算的加运算符重载函数是不益采用返回引用方式编写的,当然如果一定要返回引用,我们可以在堆内存中动态开辟空间存储数据,但是这么做会导致额外的系统开销,同时也会让程序更难读懂。 


  对于递增运算符来说,它的意义在于能够改变自身,返回引用的函数是可以作为左值参与运算的,所以作为单目运算符,重载它的函数采用返回引用的方式编写是最合适的。 

  如果我们修改递增运算符重载函数为值返回状态的时候,又会出现什么奇怪的现象呢? 

  代码如下:

        Test operator ++()  
        {  
            return this->a++;  
        }

  表面上是发现不出什么特别明显的问题的,但是在main()函数中++(++c);的执行结果却出乎意料,理论上应该是204的值,却只是203,这是为什么呢?

  因为当函数是值返回状态的时候括号内的++c返回的不是c本身而是临时变量,用临时变量参与括号外的++运算,当然c的值也就只改变了一次。结果为203而不是204。 

  对于运算符重载函数来说,最后我们还要注意一个问题,当运算符重载函数的形式参数类型全部为内部类型的时候,将不能重载
--------------------------------

  在前一节中曾提到过,C++中运行时的多态性主要是通过虚函数来实现的,而编译时的多态性是由函数重载和运算符重载来实现的。这一系列我将主要讲解C++中有关运算符重载方面的内容。在每一个系列讲解之前,都会有它的一些基础知识需要我们去理解。而运算符重载的基础就是运算符重载函数。所以今天主要讲的是运算符重载函数。

  1.运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用域不同类型的数据导致不同行为的发生。比如

C++运算重载
1 int i;
2 int i1=10,i2=10;
3 i=i1+i2;
4 std::cout<<"i1+i2="<<i<<std::endl;
5
6 double d;
7 double d1=20,d2=20;
8 d=d1+d2;
9 std::cout<<"d1+d2="<<d<<std::endl;
C++运算重载

在这个程序里"+"既完成两个整形数的加法运算,又完成了双精度型的加法运算。为什么同一个运算符"+"可以用于完成不同类型的数据的加法运算?这是因为C++针对预定义基本数据类型已经对"+"运算符做了适当的重载。在编译程序编译不同类型数据的加法表达式时,会自动调用相应类型的加法运算符重载函数。但是C++中所提供的预定义的基本数据类型毕竟是有限的,在解决一些实际的问题时,往往需要用户自定义数据类型。比如高中数学里所提到的复数:

C++运算重载
 1 class Complex //复数类
2 {
3 public:
4 double real;//实数
5 double imag;//虚数
6 Complex(double real=0,double imag=0)
7 {
8 this->real=real;
9 this->imag=imag;
10 }
11 }
C++运算重载

假如我们建立两个复数,并用"+"运算符让它们直接相加:

1 Complex com1(10,10),com2(20,20),sum;
2 sum=com1+com2;

那么会提示没有与这些操作数匹配的 "+" 运算符的错误。这是因为Complex类类型不是预定义类型,系统没用对该类型的数据进行加法运算符函数的重载。C++就为运算符重载提供了一种方法,即运算符重载函数。其函数名字规定为operator后紧跟重载运算符。比如:operator+(),operator*()等。现在我们给上述程序声明一个加法运算符的重载函数用于完成复数的加法运算:

C++运算重载
 1 #include "stdafx.h"
2 #include <iostream>
3
4 class Complex //复数类
5 {
6 public:
7 double real;//实数
8 double imag;//虚数
9 Complex(double real=0,double imag=0)
10 {
11 this->real=real;
12 this->imag=imag;
13 }
14 };
15
16 Complex operator+(Complex com1,Complex com2)//运算符重载函数
17 {
18 return Complex(com1.real+com2.real,com1.imag+com2.imag);
19 }
20
21 int main()
22 {
23 Complex com1(10,10),com2(20,20),sum;
24 sum=com1+com2;//或sum=operator+(com1,com2)
25
26 std::cout<<"sum的实数部分为"<<sum.real<<std::endl;
27 std::cout<<"sum的虚数部分为"<<sum.imag<<"i"<<std::endl;
28
29 return0;
30 }
C++运算重载

相关文章:

  • 2021-07-08
  • 2021-07-31
  • 2021-08-23
  • 2021-11-30
猜你喜欢
  • 2022-01-19
  • 2021-09-28
  • 2021-11-17
  • 2021-10-07
  • 2022-01-01
  • 2020-03-21
  • 2019-08-25
相关资源
相似解决方案