C++之运算符重载(上)

1、概念

所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。

运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的, 但由于C++已经对运算符”+”进行了重载,所以就能适用于int, float, doUble类型的运算。

又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对 象cout 配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象 cin 配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同 的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<< “和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。
现在要讨论的问题是:用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。

  • 运算符重载入门技术推演
    • 为什么会用运算符重载机制
      用复数类举例
Complex c3 = c1 + c2; 

原因 Complex是用户自定义类型,编译器根本不知道如何进行加减.因此编译器给提供了一种机制,让用户自己去完成,自定义类型的加减操作。这个机制就是运算符重载机制

  • 运算符重载的本质是一个函数
#include <stdio.h>

// a + bi
class Complex
{
    friend Complex add (Complex &a, Complex &b);
    friend Complex operator+ (Complex &a, Complex &b);
public:
    Complex()
    {
        m_a = 0;
        m_b = 0;
    }
    Complex (int a, int b)
    {
        m_a = a;
        m_b = b;
    }

    void print ()
    {
        printf ("%d + %di\n", m_a, m_b);
    }

    Complex operator- (Complex &b)
    {
        Complex tmp(m_a-b.m_a, m_b-b.m_b);

        return tmp;
    }

private:
    int m_a;
    int m_b;
};

// 全局函数
Complex add (Complex &a, Complex &b)
{
    Complex tmp(a.m_a+b.m_a, a.m_b+b.m_b);

    return tmp;
}

// 运算符重载: 本质是一个函数
// 函数名字组成:operator + 要重载的运算符
Complex operator+ (Complex &a, Complex &b)
{
    Complex tmp(a.m_a+b.m_a, a.m_b+b.m_b);

    return tmp;
}

// 运算符重载:给运算符重新定义功能
// 1、写函数名:operator + 重载的运算符
// 2、根据运算需求  写函数的 参数列表
// 3、根据需求 写出函数返回值的类型 
int main()
{
    Complex c1(1,2), c2(3,4), c3, c4;
    c1.print();
    c2.print();

    // c3 = c1 + c2; // Complex 自定义的类,编译器不知道以什么规则进行运算
    // c3 = add(c1, c2);
    // c3 = operator+(c1, c2);
    c3 = c1 + c2;  // ===> operator+(c1, c2);
    c3.print();

    // c4 = c3.operator-(c2);  // c3 - c2
    c4 = c3 - c2; // ====>  c4 = c3.operator-(c2)/operator-(c1, c2);

    // ( operator+(c1, c3) ).operator-(c2)
    c4 = c1 + c3 - c2;
    c4.print();


    return 0;
}

int mai3_1()
{
    int a = 10, b= 20, c;
    c = a + b;    // 基础的数据做运算,编译器直到怎么做

    printf ("c = %d\n", c);

    return 0;
}

2、限制

这里写图片描述

3、基础

这里写图片描述
例如:

//全局函数 完成 +操作符 重载
Complex operator+(Complex &c1, Complex &c2)
//类成员函数 完成 -操作符 重载
Complex operator-(Complex &c2)
  • 运算符重载的两种方法
    这里写图片描述
    这里写图片描述

例如1:通过类成员函数完成-操作符重载

//函数声明 Complex operator-(Complex &c2)
//函数调用分析
//用类成员函数实现-运算符重载
    Complex c4 = c1 - c2;
    c4.printCom();
    //c1.operator-(c2);

例如2:通过全局函数方法完成+操作符重载

//函数声明 Complex operator+(Complex &c1, Complex &c2) 
//函数调用分析
int main()
{
        Complex c1(1, 2), c2(3, 4);
        //Complex c31 = operator+(c1, c2);
Complex c3 = c1 + c2; 
c3.printCom();
}

这里写图片描述
例如3

//前置++操作符 用全局函数实现 
Complex& operator++(Complex &c1) 
{
    c1.a ++;   
    c1.b ++;
    return c1;  
}
//调用方法 
++c1 ;               //需要写出操作符重载函数原形 
c1.printCom();

//运算符重载函数名定义 
//首先承认操作符重载是一个函数 定义函数名operator++ 
//分析函数参数 根据左右操作数的个数,operator++(Complex &c1) 
//分析函数返回值Complex& operator++(Complex &c1) 返回它自身

例如4

//4.1前置--操作符 成员函数实现
Complex& operator--()
{
    this->a--;
    this->b--;
    return *this;
}

//4.2调用方法 
--c1; 
c1.printCom(); 
//4.3前置—运算符重载函数名定义 
//c1.operator–()

例如5

//5.1 //后置++ 操作符 用全局函数实现
Complex operator++(Complex &c1, int) 
{
    Complex tmp = c1;
    c1.a++;
    c1.b++;
    return tmp;
}

//5.2 调用方法 
c1 ++ ; //先使用 后++ 
//5.3 后置++运算符重载函数名定义 
Complex operator++(Complex &c1, int)

函数占位参数 和 前置++ 相区别

例如6

//6.1 后置— 操作符 用类成员函数实现
Complex operator--(int) 
{
    Complex tmp = *this;
    this->a--;
    this->b--;
    return tmp;
}

//6.2 调用方法 
c1 ++ ; //先使用 后++ 
//6.3 后置–运算符重载函数名定义 
Complex operator--(int) //函数占位参数 和 前置– 相区别

前置和后置运算符总结
C++中通过一个占位参数来区分前置运算和后置运算

#include <iostream>
using namespace std;

class Complex
{
private:
    int a;
    int b;
    //全局函数 重载+运算符
    friend Complex operator+(Complex &c1, Complex &c2);
    //重载 前置++
    friend Complex& operator++(Complex &c1);
    friend Complex operator++(Complex &c1, int);
public:
    Complex(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void printCom()
    {
        cout<<a<<" + " << b << "i" <<endl;
    }
public:

    //成员函数法 实现 -运算符重载
     Complex operator-(Complex &c2)
    {
        Complex tmp(this->a - c2.a, this->b - c2.b);
        return tmp;
    }

     //前置--
    Complex& operator--()
    {
        this->a --;
        this->b --;
        return *this;
    }

    //后置--
    Complex operator--(int)
    {
        Complex tmp = *this;
        this->a--;
        this->b--;
        return tmp;
    }
};

//全局函数法 实现 + 运算符重载
Complex operator+(Complex &c1, Complex &c2)
{
    Complex tmp(c1.a + c2.a, c1.b + c2.b);
    return tmp;
}

//前置++
Complex& operator++(Complex &c1)
{
    c1.a++;
    c1.b++;
    return c1;
}

//后置++
Complex operator++(Complex &c1, int)
{
    //先使用 在让c1加加
    Complex tmp = c1;
    //return c1;
    c1.a ++;
    c1.b ++;
    return tmp;
}

/*
全局函数、类成员函数方法实现运算符重载步骤
    1)要承认操作符重载是一个函数,写出函数名称
    2)根据操作数,写出函数参数 
    3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
*/
void main()
{
    Complex c1(1, 2), c2(3, 4);


    //1 全局函数法 实现 + 运算符重载
    // Complex operator+(Complex &c1, Complex &c2);
    Complex c3 = c1 + c2;
    c3.printCom();

    //2 成员函数 法 实现 -运算符重载
    //c1.operator-(c2);
    //Complex operator-(Complex &c2)
    Complex c4 = c1 - c2;
    c4.printCom();

    //前置++操作符 用全局函数实现
    ++c1;
    c1.printCom();

    //前置--操作符 成员函数方法
    --c1;
    c1.printCom();
    //Complex& operator++(Complex &c1)
    //c1.operator--();

    //后置++操作符 用全局函数实现
    c1++;
    c1.printCom();

    //后置--操作符 用成员函数实现
    c1--;
    c1.printCom();
    //c1.operator--()

    cout<<"hello..."<<endl;
    system("pause");
    return ;
}

友元函数实现操作符重载的应用场景
1) 友元函数和成员函数选择方法

  • 当无法修改左操作数的类时,使用全局函数进行重载
  • =, [], ()和->操作符只能通过成员函数进行重载
    2)用友元函数重载<< >> 操作符
  • istream 和 ostream 是 C++ 的预定义流类
  • cin 是 istream 的对象,cout 是 ostream 的对象
  • 运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
  • 运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
  • 用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型

a)用全局函数方法实现<<操作符重载

ostream& operator<<(ostream &out, Complex &c1)
{
    //out<<"12345,生活真是苦"<<endl;
    out<<c1.a<<" + "<<c1.b<<"i "<<endl;
    return out;
}

/调用方法 
cout<<c1; 
//链式编程支持 
cout<<c1<<"abcc"; 
//cout.operator<<(c1).operator<<("abcd"); 
/函数返回值充当左值 需要返回一个引用

b)类成员函数方法实现<<操作符重载

  • 因无法拿到cout这个类的源码
  • cout.operator<<(c1);

友元函数重载操作符使用注意点
a)友元函数重载运算符常用于运算符的左右操作数类型不同的情况
这里写图片描述
b)其他

  • 在第一个参数需要隐式转换的情形下,使用友员函数重载运算符是正确的选择
  • 友员函数没有 this 指针,所需操作数都必须在参数表显式声明,很容易实现类型的隐式转换
  • C++中不能用友员函数重载的运算符有 = () [] ->

友元函数案例vector类

#include <iostream>
using namespace std;

//为vector类重载流插入运算符和提取运算符 
class vector
{ 
public :
    vector( int size =1 ) ;       
    ~vector() ;
    int & operator[]( int i ) ;
    friend ostream & operator << ( ostream & output , vector & ) ;
    friend istream & operator >> ( istream & input, vector & ) ;
private :  
    int * v ;     
    int len ;
};

vector::vector( int size ) 
{ 
    if (size <= 0 || size > 100 )
    { 
        cout << "The size of " << size << " is null !\n" ; abort() ;  
    }
    v = new int[ size ] ;  len = size ;
}

vector :: ~vector() 
{ 
    delete[] v ;  
    len = 0 ; 
}

int &vector::operator[]( int i )        
{ 
    if( i >=0 && i < len )  return v[ i ] ;
    cout << "The subscript " << i << " is outside !\n" ;  abort() ;
}
ostream & operator << ( ostream & output, vector & ary )
{ 
    for(int i = 0 ; i < ary.len ; i ++ )  
        output << ary[ i ] << "  " ;
    output << endl ;
    return output ;
}
istream & operator >> ( istream & input, vector & ary ) 
{ 
    for( int i = 0 ; i < ary.len ; i ++ )  
        input >> ary[ i ] ;
    return  input ;
}

void main()
{ 
    int k ;
    cout << "Input the length of vector A :\n" ;     
    cin >> k ;
    vector A( k ) ;
    cout << "Input the elements of vector A :\n" ;     
    cin >> A ;
    cout << "Output the elements of vector A :\n" ;
    cout << A ;
    system("pause");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值