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 - c2c4 = 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");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

4.提高 1.运算符重载机制 编译器实现运算符重载实际上就是通过函数重载实现的&#xff0c;可分为全局函数方式&#xff0c;也可分为成员函数方式进行重载&#xff0c;并没有改变原操作符的属性和语义。只是针对某个特定类定义一种新的数据类型操作。 2.重载赋值运算符 赋值…

Cookie / Session 的机制与安全

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Cookie和Session是为了在无状态的HTTP协议之上维护会话状态&#xff0c;使得服务器可以知道当前是和哪个客户在打交道。本文来详细讨论C…

Servlet快速入门及运行流程

一、Servlet快速入门 1.创建一个web工程 2.在JavaResource中src下创建一个包名称为com.myxq.servlet 3.在创建的servlet包当中创建一个class文件起名为FirstServlet 4.进入该class实现一个Servlet接口&#xff0c;实现它未实现的方法 重点看service方法在该方法当中写入一句话进…

C++之多继承

1.基础知识 1.1 类之间的关系 has-A&#xff0c;uses-A 和 is-A has-A 包含关系&#xff0c;用以描述一个类由多个“部件类”构成。实现has-A关系用类成员表示&#xff0c;即一个类中的数据成员是另一种已经定义的类。 常和构造函数初始化列表一起使用 uses-A 一个类部分地…

聊一聊 cookie

我们看到的 cookie 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我自己创建了一个网站&#xff0c;网址为http://ppsc.sankuai.com。在这个网页中我设置了几个cookie&#xff1a;JS…

const的用法,特别是用在函数后面

原文出处&#xff1a;http://blog.csdn.net/zcf1002797280/article/details/7816977

图解 Linux 安装 JDK1.8 、配置环境变量

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 到官网下载 JDK 1.8 https://www.oracle.com/technetwork/java/javase/downloads/index.html 2. 用 rz 命令把 jdk-8u191-linux-x6…

C++之纯虚函数和抽象类

纯虚函数和抽象类 1.基本概念 2.案例 #include <iostream> using namespace std;////面向抽象类编程(面向一套预先定义好的接口编程)//解耦合 ....模块的划分class Figure //抽象类 { public://阅读一个统一的界面(接口),让子类使用,让子类必须去实现virtual void get…

解决: -bash: $‘\302\240docker‘: command not found

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我只是运行 一条很简单的启动容器的命令&#xff0c;多次执行都报错&#xff0c;报错如题&#xff1a; -bash: $\302\240docker: comma…

【汽车取证篇】GA-T 1998-2022《汽车车载电子数据提取技术规范》(附下载)

【汽车取证篇】GA-T 1998-2022《汽车车载电子数据提取技术规范》&#xff08;附下载&#xff09; GA-T 1998-2022《汽车车载电子数据提取技术规范》标准—【蘇小沐】 总结 公众号回复关键词【汽车取证】自动获取资源合集&#xff0c;如链接失效请留言&#xff0c;便于…

解决: Client does not support authentication protocol requested by server; consider upgrading MySQL

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 在服务器上把 mysql 装好后&#xff0c;运行起来。 2. navicat 死活连接不上&#xff0c;在网上查说是要改数据库账号、密码什么的&…

C++之STL理论基础

1.基本概念 STL&#xff08;Standard Template Library&#xff0c;标准模板库)是惠普实验室开发的一系列软件的统称。虽然主要出现在C中&#xff0c;但在被引入C之前该技术就已经存在了很长的一段时间。 STL的从广义上讲分为三部分&#xff1a;algorithm&#xff08;算法&am…

解决maven打包报错:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 一、报错经历&#xff1a; 今天使用eclipse通过maven install打war包的时候&#xff0c;出现了下图所示的错误 二、问题分析&#xff1a…

STL之Vector

1.简介 vector是将元素置于一个动态数组中加以管理的容器。可以随机存取元素&#xff08;支持索引值直接存取&#xff0c;用[]操作符或at()方法&#xff0c;还支持迭代器方式存取&#xff09;。   vector尾部添加或移除元素非常快速。但是在中部或头部插入元素或移除元素比…

解决 : Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 执行 maven install 命令报错如题&#xff1a; Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:comp…

Docker 镜像 重命名

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 镜像改名命令格式&#xff1a; # 命令格式&#xff1a;docker tag 镜像id 仓库&#xff1a;标签或&#xff1a;docker tag 旧镜…

Java蓝桥杯02——第二题集锦:生日蜡烛、星期一、方格计数、猴子分香蕉

第二题 生日蜡烛(结果填空) 某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来&#xff0c;他一共吹熄了236根蜡烛。 请问&#xff0c;他从多少岁开始过生日party的&#xff1f; 请填写他开始过生日party的年龄数。 注意&a…

解决:Error response from daemon: Get https://index.docker.io/v1/search?q=openjdkn=25: dial tcp: looku

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 我只是想查一个 mysql 镜像。执行命令&#xff1a; docker search mysql 。报错如下&#xff1a; Error response from daemon…

安装 Git ( Windows、linux、Mac)

安装 Git 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 是时候动手尝试下 Git 了&#xff0c;不过得先安装好它。有许多种安装方式&#xff0c;主要分为两种&#xff0c;一种是通过编…

STL之函数适配器

1.理论知识 2.常用函数适配器 标准库提供一组函数适配器&#xff0c;用来特殊化或者扩展一元和二元函数对象。常用适配器是&#xff1a; 1绑定器&#xff08;binder&#xff09;: binder通过把二元函数对象的一个实参绑定到一个特殊的值上&#xff0c;将其转换成一元函数对象…