C++运算符重载

C++运算符重载

C++运算符重载:使对象的运算表现得和编译器内置类型一样

C++实现复数类实现运算符重载

C++类对象操作符重载函数函数时,会优先调用类的成员方法,没有找到再去全局去寻找对应的方法

在调用某些操作符重载函数时,如果类型不满足条件可以进行产生临时对象,然后再进行操作符重载。

++/-- 表示自增运算符,也称为单目运算符 i++,++i怎么进行区分呢。C++中将前置++i,利用operator++()表示;后置i++,利用operator++(int)表示;这样就构成了函数重载,实现了i++和++i分离。

#include<iostream>
using namespace std;
class Complex
{
public:Complex(int r = 0, int i = 0) : mreal(r), mimage(i) { cout << "Complex(int,int)" << endl; }Complex(const Complex &src) { cout << "Complex(const Complex&)" << endl; }// 这里不能将Complex替换为Complex&,因为这里返回的对象是局部的,出了作用域就会被析构了Complex operator+(const Complex &src){cout << "Complex operator+(const Complex &src)" << endl;// method 1 这里会产生一个对象,到时候会在调用这个函数的时候产生一个临时对象/*Complex comp;comp.mreal = this->mreal + src.mreal;comp.mimage = this->mimage + src.mimage;return comp;*/// method 2 直接在调用这个函数的栈上生成临时对象,就不会在这里产生一个对象return Complex(this->mreal + src.mreal, this->mimage + src.mimage);}~Complex() { cout << "~Complex()" << endl; }void show(){cout << "mreal:" << mreal << " mimage:" << mimage << endl;}// ++i前置++Complex& operator++(){mreal += 1;mimage += 1;return *this;}// i++后置++Complex operator++(int){// Complex c = *this;// mreal += 1;// mimage += 1;// return *this;return Complex(mreal++, mimage++);}void operator+=(const Complex& src){mreal += src.mreal;mimage = src.mimage;}private:int mreal;int mimage;friend Complex operator+(const Complex &src1, const Complex &src2);//声明成友元函数就可以访问私有属性friend ostream &operator<<(ostream &out, const Complex &src);friend istream &operator>>(istream &in, Complex &src);
};Complex operator+(const Complex& src1,const Complex& src2)
{cout << "Complex operator+(const Complex& src1,const Complex& src2)" << endl;return Complex(src1.mreal + src2.mreal, src1.mimage + src2.mimage);
}ostream& operator<<(ostream& out,const Complex& src)
{out << "mreal:" << src.mreal << " mimage:" << src.mimage << endl;return out;
}
istream& operator>>(istream& in,Complex& src)
{in >> src.mreal >> src.mimage;return in;
}int main()
{Complex c1(10, 10);Complex c2(20, 20);cout << "-----------" << endl;Complex c3 = c1 + c2;//c1+c2等价于c1.operator+(c2),所以+操作符重载只有一个参数cout << "-----------" << endl;c3.show();Complex c4 = c3 + 20;//这里会将20进行转化成Complex类,调用构造函数c4.show();// 编译器做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法)// 如果没有成员方法,就在全局作用域找合适的运算符重载函数// Complex c5 = 30 + c4;//如果没有定义全局函数,这里会转化错误,没有办法将30转化为ComplexComplex c5 = 30 + c4;//定义了全局的operator+后就能调用::operator+(30,c4);c5.show();c5++;c5.show();cout << c5;/*++/-- 表示自增运算符,也称为单目运算符  i++,++i怎么进行区分呢C++中将前置++i,利用operator++()表示;后置i++,利用operator++(int)表示;这样就构成了函数重载,实现了i++和++i分离*/cin >> c5;cout << c5;return 0;
}

这里其实存在一个细节点,可以用于节省资源,如下代码所示:

Complex& operator++()
{mreal += 1;mimage += 1;return *this;}// i++后置++Complex operator++(int){// Complex c = *this;// mreal += 1;// mimage += 1;// return *this;return Complex(mreal++, mimage++);}

可以看到前置运算符++返回的是引用,而后置++返回的是一个新对象,所以一般没有区别的时候尽量使用前置++的操作符运算,这样就会节省对象的创建和析构。

C++自定义实现String

String内部实现最复杂的是operator+()操作符重载,涉及了堆内存的开辟和释放问题。

#include<iostream>
#include<string.h>using namespace std;class String
{
public:String(const char* p=nullptr){if(p!=nullptr){_pstr = new char[strlen(p) + 1];strcpy(_pstr, p);}else{_pstr = new char[1];*_pstr = '\0';}}~String(){delete[] _pstr;_pstr = nullptr;}String(const String& src){_pstr = new char[strlen(src._pstr) + 1];strcpy(_pstr, src._pstr);}String& operator=(const String& src){if(this==&src)return *this;delete[] _pstr;_pstr = new char[strlen(src._pstr) + 1];strcpy(_pstr, src._pstr);return *this;}bool operator>(const String &src) const{return strcmp(_pstr, src._pstr) > 0;}bool operator==(const String &src) const{return strcmp(_pstr, src._pstr) == 0;}bool operator<(const String &src) const{return strcmp(_pstr, src._pstr) < 0;}int length()const{return strlen(_pstr);}char &operator[](int index) { return _pstr[index]; }const char &operator[](int index) const { return _pstr[index]; }const char *c_str() const { return _pstr; }private:char *_pstr;friend String operator+(const String &lsrc, const String &rsrc);friend ostream &operator<<(ostream &out, const String &src);friend istream &operator>>(istream &in, String &src);
};String operator+(const String &lsrc,const String &rsrc)
{// char *temp = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];// strcpy(temp, lsrc._pstr);// strcat(temp, rsrc._pstr);// String s(temp);// delete[] temp;String s;s._pstr = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];strcpy(s._pstr, lsrc._pstr);strcat(s._pstr, rsrc._pstr);return s;
}
ostream& operator<<(ostream& out,const String& src)
{out << src._pstr;return out;
}
istream &operator>>(istream &in, String &src)
{in >> src._pstr;return in;
}int main()
{String str1;String str2 = "aaa";String str3 = "bbb";String str4 = str2 + str3;String str5 = str2 + "ccc";String str6 = "ddd" + str2;cout << "str6:" << str6 << endl;if(str5>str6){cout << str5 << ">" << str6 << endl;}else{cout << str5 << "<" << str6 << endl;}int len = str6.length();for (int i = 0; i < len;i++){cout << str6[i] << " ";}cout << endl;char buf[1024] = {0};strcpy(buf, str6.c_str());cout << "buf:" << buf << endl;return 0;
}

迭代器(iterator)是C++容器的一大特性,迭代器可以透明的访问容器内部元素的值(不用知道容器底层的数据结构,数组,链表等)。

泛型算法参数接收的都是迭代器。

泛型算法-全局的函数-给所有的容器使用的。

泛型算法,有一套方式,能够统一的遍历所有的容器内部的元素-迭代器。

实现String容器的迭代器:

#include<iostream>
#include<string.h>using namespace std;class String
{
public:String(const char* p=nullptr){if(p!=nullptr){_pstr = new char[strlen(p) + 1];strcpy(_pstr, p);}else{_pstr = new char[1];*_pstr = '\0';}}~String(){delete[] _pstr;_pstr = nullptr;}String(const String& src){_pstr = new char[strlen(src._pstr) + 1];strcpy(_pstr, src._pstr);}String& operator=(const String& src){if(this==&src)return *this;delete[] _pstr;_pstr = new char[strlen(src._pstr) + 1];strcpy(_pstr, src._pstr);return *this;}bool operator>(const String &src) const{return strcmp(_pstr, src._pstr) > 0;}bool operator==(const String &src) const{return strcmp(_pstr, src._pstr) == 0;}bool operator<(const String &src) const{return strcmp(_pstr, src._pstr) < 0;}int length()const{return strlen(_pstr);}char &operator[](int index) { return _pstr[index]; }const char &operator[](int index) const { return _pstr[index]; }const char *c_str() const { return _pstr; }class iterator{public:iterator(char *p = nullptr) : _p(p){}void operator++(){++_p;}bool operator!=(const iterator& src){if(_p!=src._p)return true;return false;}char& operator*(){return *_p;}private:char* _p;};iterator begin() { return iterator(_pstr); };iterator end() { return iterator(_pstr + length()); }private:char *_pstr;friend String operator+(const String &lsrc, const String &rsrc);friend ostream &operator<<(ostream &out, const String &src);friend istream &operator>>(istream &in, String &src);
};String operator+(const String &lsrc,const String &rsrc)
{String s;s._pstr = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];strcpy(s._pstr, lsrc._pstr);strcat(s._pstr, rsrc._pstr);return s;
}
ostream& operator<<(ostream& out,const String& src)
{out << src._pstr;return out;
}
istream &operator>>(istream &in, String &src)
{in >> src._pstr;return in;
}int main()
{String a = "ababas";// 迭代器的作用:提供统一的形式,来遍历容器String::iterator it = a.begin();for (; it != a.end();++it){cout << *it << " ";}return 0;
}

C++实现vector(包含迭代器)

在原先的内容基础上添加了迭代器部分,Vector实现了元素内存开辟和对象创建的分离,当然内存回收和对象析构也进行了分离。

#include <iostream>
using namespace std;template <typename T>
class Allocator
{
public:T *allocator(size_t size) // 负责内存开辟,size个数量{return (T *)malloc(sizeof(T) * size);}void deallocator(T *p) // 内存释放{free(p);}void construct(T *p, const T &val) // 对象创建{// 更多new初始化方法 https://blog.csdn.net/qq_45041871/article/details/132251733new (p) T(val); // 使用的是定位new,将val传到地址为p的空间去,p地址指向val}void destroy(T *p) // 对象析构{p->~T();}
};
template <typename T, typename Alloc = Allocator<T>>
class Vector
{
public:Vector(int size = 5){// 需要将内存开辟和对象构造分开处理// _first = new T[size];_first = _allocator.allocator(size); // 只开辟空间_last = _first;_end = _first + size; // 这就相当于指针遍历移动}~Vector(){// 析构容器中有效的元素,然后释放_first指针所指向的内存// delete[] _first;for (T *p = _first; p != _last; ++p){_allocator.destroy(p);}_allocator.deallocator(_first);_first = _last = _end = nullptr;}Vector(const Vector<T> &src){int size = src._end - src._first;// _first = new T[size];_first = _allocator.allocator(size);for (int i = 0; i < src._last - src._first; i++){// _first[i] = src._first[i];_allocator.construct(_first + i, src._first[i]);}_last = _first + src._last - src._first;_end = _first + size;}Vector<T> &operator=(const Vector<T> &src){if (this == &src)return *this;// delete[] _first;for (T *p = _first; p != _last; p++){_allocator.destroy(p);}_allocator.deallocator(_first);int size = src._end - src._first;_first = new T[size];for (int i = 0; i < src._last - src._first; i++){// _first[i] = src._first[i];_allocator.construct(_first + i, src._first[i]);}_last = _first + src._last - src._first;_end = _first + size;return *this;}void push_back(T &val){if (full())expand();_allocator.construct(_last, val);_last++;}void pop_back(){if (empty())return;_last--;_allocator.destroy(_last);}T back() const{return *(_last - 1);}bool full() const { return _last == _end; }bool empty() const { return _last == _first; }int size() { return _last - _first; }T& operator[](int index){if(index<0||index>size())throw "OutOfRangeException";return _first[index];}class iterator{public:iterator(T *ptr=nullptr):_ptr(ptr){}bool operator!=(const iterator &it) const{ return it._ptr != _ptr;}void operator++() { ++_ptr; }T &operator*() { return *_ptr; }const T &operator*() const { return *_ptr; }private:T *_ptr;};iterator begin() { return iterator(_first); }iterator end() { return iterator(_last); }private:T *_first; // 指向数组起始的位置T *_last;  // 指向数组中有效元素的后继位置T *_end;   // 指向数组空间的后继位置iterator _iterator;Alloc _allocator; // 定义容器的空间配置器void expand(){int size = _end - _first;// T *temp = new T[size * 2];T *temp = _allocator.allocator(size * 2);for (int i = 0; i < size; i++){// temp[i] = _first[i];_allocator.construct(temp + i, _first[i]);}// delete[] _first;for (T *p = _first; p != _last; p++){_allocator.destroy(p);}_allocator.deallocator(_first);_first = temp;_last = _first + size;_end = _last + size;}
};
int main()
{Vector<int> v;for (int i = 0; i < 20;i++){v.push_back(i);}int size = v.size();for (int i = 0; i < size;i++){cout << v[i] << " ";}cout << endl;Vector<int>::iterator it = v.begin();for (; it != v.end();++it){cout << *it << " ";}cout<<endl;return 0;
}

iterator失效问题

迭代器失效问题?

1、迭代器为什么会失效?

  • 当容器调用erase方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。
  • 当容器调用insert方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。

迭代器情况:

首元素 -> 插入点/删除点 -> 末尾元素


原始的vector容器中的迭代器是怎么解决这个问题的呢?

通过迭代器erase和insert函数返回当前迭代器的情况进行处理。

如下代码所示:

#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> vec;for (int i = 0; i < 20; ++i){vec.push_back(rand() % 100 + 1);}vector<int>::iterator it = vec.begin();#if 0//给vec容器中所有偶数前面添加一个小于偶数值1的数字for (; it != vec.end(); ++it){if (*it % 2 == 0){//这里会产生迭代器失效问题,第一次调用insert之后,iterator就失效了vec.insert(it, *it - 1);//在当前迭代器it上插入值为val,如果没有break就会出现问题,程序会崩溃}}//把容器vec容器的偶数全部删除for (; it != vec.end(); ++it){if (*it % 2 == 0){//这里会产生迭代器失效的问题,第一次调用了erase函数之后,迭代器it就会失效vec.erase(it);//erase删除当前的位置的迭代器,这里如果没有break就会出现问题}}
#endiffor (; it != vec.end(); ++it){if (*it % 2 == 0){it=vec.insert(it, *it - 1);//插入一个新元素后,迭代器就会指向该元素,并把之前指向的往后移it++;}}for (; it != vec.end();){if (*it % 2 == 0){it=vec.erase(it);//如果删除了当前迭代器,那么就会将下一个元素的迭代器返回回来}else{++it;}}return 0;
}

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

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

相关文章

创建密码库/创建用户帐户/更新 Ansible 库的密钥/ 配置cron作业

目录 创建密码库 创建用户帐户 更新 Ansible 库的密钥 配置cron作业 创建密码库 按照下方所述&#xff0c;创建一个 Ansible 库来存储用户密码&#xff1a; 库名称为 /home/curtis/ansible/locker.yml 库中含有两个变量&#xff0c;名称如下&#xff1a; pw_developer&#…

YOLOv5、YOLOv8改进:S2注意力机制

目录 1.简介 2.YOLOv5改进 2.1增加以下S2-MLPv2.yaml文件 2.2common.py配置 2.3yolo.py配置 1.简介 S2-MLPv2注意力机制 最近&#xff0c;出现了基于 MLP 的视觉主干。与 CNN 和视觉Transformer相比&#xff0c;基于 MLP 的视觉架构具有较少的归纳偏差&#xff0c;在图像识…

中国剩余定理及扩展

目录 中国剩余定理解释 中国剩余定理扩展——求解模数不互质情况下的线性方程组&#xff1a; 代码实现&#xff1a; 互质&#xff1a; 非互质&#xff1a; 中国剩余定理解释 在《孙子算经》中有这样一个问题&#xff1a;“今有物不知其数&#xff0c;三三数之剩二&#x…

go es实例

go es实例 1、下载第三方库 go get github.com/olivere/elastic下载过程中出现如下报错&#xff1a; 解决方案&#xff1a; 2、示例 import package mainimport ("context""encoding/json""fmt""reflect""time""…

【前端】快速掌握HTML+CSS核心知识点

文章目录 1.HTML核心基础知识1.1.编写第一个HTML网页1.2.超链接a标签和路径1.3.图像img标签的用法1.4.表格table标签用法1.5.列表ul、ol、dl标签用法1.6.表单form标签用法1.7.区块标签和行内标签用法 2.CSS核心基础知识2.1.CSS标签选择器viewport布局2.2.CSS样式的几种写法2.3.…

【Linux取经路】解析环境变量,提升系统控制力

文章目录 一、进程优先级1.1 什么是优先级&#xff1f;1.2 为什么会有优先级&#xff1f;1.3 小结 二、Linux系统中的优先级2.1 查看进程优先级2.2 PRI and NI2.3 修改进程优先级2.4 进程优先级的实现原理2.5 一些名词解释 三、环境变量3.1 基本概念3.2 PATH&#xff1a;Linux系…

k8s 常见面试题

前段时间在这个视频中分享了 https://github.com/bregman-arie/devops-exercises 这个知识仓库。 这次继续分享里面的内容&#xff0c;本次主要以 k8s 相关的问题为主。 k8s 是什么&#xff0c;为什么企业选择使用它 k8s 是一个开源应用&#xff0c;给用户提供了管理、部署、扩…

Learning to Super-resolve Dynamic Scenes for Neuromorphic Spike Camera论文笔记

摘要 脉冲相机使用了“integrate and fire”机制来生成连续的脉冲流&#xff0c;以极高的时间分辨率来记录动态光照强度。但是极高的时间分辨率导致了受限的空间分辨率&#xff0c;致使重建出的图像无法很好保留原始场景的细节。为了解决这个问题&#xff0c;这篇文章提出了Sp…

idea2023 springboot2.7.5+mybatisplus3.5.2+jsp 初学单表增删改查

创建项目 修改pom.xml 为2.7.5 引入mybatisplus 2.1 修改pom.xml <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!--mysq…

【STM32 学习】电源解析(VCC、VDD、VREF+、VBAT)

VCC电源电压GND电源供电负电压&#xff08;通常接地&#xff09;VDD模块工作正电压VSS模块工作负电压VREFADC参考正电压VREF-ADC参考负电压VBAT电池或其他电源供电VDDA模拟供电正电压VSSA模拟供电负电压 一、VCC&#xff08;供电电压&#xff09; VCC是指芯片的电源电压&#…

MNIST手写数字数据集+7000张图片下载

MNIST手写数字图像数据集是一个经典的用于图像分类任务的数据集&#xff0c;其中包含了大量的手写数字图像样本 数据集点击下载&#xff1a; MNIST手写数字数据集7000张图片.rar

函数栈帧理解

本文是从汇编角度来展示的函数调用&#xff0c;而且是在vs2013下根据调试展开的探究&#xff0c;其它平台在一些指令上会有点不同&#xff0c;指令不多&#xff0c;简单记忆一下即可&#xff0c;在我前些年的学习中&#xff0c;学的这几句汇编指令对我调试找错误起了不小的作用…

【令牌桶算法与漏桶算法】

&#x1f4a7; 令牌桶算法与漏桶算法 \color{#FF1493}{令牌桶算法与漏桶算法} 令牌桶算法与漏桶算法&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专…

【前端|JS实战第1篇】使用JS来实现属于自己的贪吃蛇游戏!

前言 贪吃蛇游戏是经典的小游戏&#xff0c;也是学习前端JS的一个很好的练习项目。在本教程中&#xff0c;我们将使用 JavaScript 来逐步构建一个贪吃蛇游戏。我们会从创建游戏区域开始&#xff0c;逐步添加蛇的移动、食物的生成以及游戏逻辑等功能。 &#x1f680; 作者简介&a…

韦东山-电子量产工具项目:业务系统

代码结构 所有代码都已通过测试跑通&#xff0c;其中代码结构如下&#xff1a; 一、include文件夹 1.1 common.h #ifndef _COMMON_H #define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽…

java八股文面试[java基础]——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…

Python web实战之细说 Django 的单元测试

关键词&#xff1a; Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好&#xff0c;今天&#xff0c;我将带领大家进入 Python Web 开发的新世界&#xff0c;深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解&#xff…

ubuntu安装Microsoft Edge并设置为中文

1、下载 edge.deb 版本并安装 sudo dpkg -i microsoft-edg.deb 2. 设置默认中文显示 如果是通过.deb方式安装的&#xff1a; 打开默认安装路径下的microsoft-edge-dev文件&#xff0c;在文件最开头加上: export LANGUAGEZH-CN.UTF-8 &#xff0c;保存退出。 cd /opt/micr…

PHP8的字符串操作3-PHP8知识详解

今天继续分享字符串的操作&#xff0c;前面说到了字符串的去除空格和特殊字符&#xff0c;获取字符串的长度&#xff0c;截取字符串、检索字符串。 今天继续分享字符串的其他操作。如&#xff1a;替换字符串、分割和合成字符串。 5、替换字符串 替换字符串就是对指定字符串中…

【算法系列篇】滑动窗口

文章目录 前言什么是滑动窗口1.长度最小的子数组1.1 题目要求1.2 做题思路 1.3 Java代码实现2.无重复字符的最长子串2.1 题目要求2.2 做题思路2.3 Java代码实现 3.最大连续1的个数 III3.1 题目要求3.2 做题思路3.3 Java代码实现 4.将x减到0的最小操作数4.1 题目要求4.2 做题思路…