03c++重载运算符

1、深入理解new和delete原理

#include<iostream>
using namespace std;/*
new 和 delete
1、malloc和new的区别 new = 内存开辟+构造函数
2、free和 delete的区别 delete = 内存回收+析构函数
开辟失败malloc返nullptr ,new抛出bad_alloc异常new->operator new
delete ->operator delete
*///先调用operator new开辟内存空间然后调对象的构造函数
//void* operator new(size_t size)
//{
//	void* p = malloc(size);
//	if (p == nullptr)
//		throw bad_alloc();
//	cout << "operator new  " << p << endl;
//	return p;
//}
调用delete p;调用p指向对象的析构函数,在调用operator delete释放内存空间
//
//void operator delete(void* ptr)
//{
//	cout << "operator delete  " << ptr << endl;
//
//	free(ptr);
//}//先调用operator new开辟内存空间然后调对象的构造函数/*
new和delete能混用吗? 为什么区分单个元素和数组的内存分配和释放呢?
new delete
new[] delete[]
对于普通的编译器内置类型new/delete[]  new[]/delete可以混用自定义的类型有析构函数,为了正确调用,在开辟对象数组的时候会多开辟四个字节,记录对象的个数
*/
void* operator new[](size_t size){void* p = malloc(size);if (p == nullptr)throw bad_alloc();cout << "operator new addr[]" << p << endl;return p;}//调用delete p;调用p指向对象的析构函数,在调用operator delete释放内存空间void operator delete[](void* ptr){cout << "operator delete addr[]" << ptr << endl;free(ptr);}class Test{public:Test(int data = 10){cout << "Test()" << endl;}~Test(){cout << "~Test()" << endl;}};int main(){//try//{//	int* p = new int;//	delete p;//	int* q = new int[10];//	delete[]q;//}//catch (const bad_alloc& err)//{//	cerr << err.what() << endl;//}//Test* p1 = new Test();//delete[]p1; //报错Test* p2 = new  Test[5]; //delete p2;错误 Test[0]析构,直接俄free(p2)cout << "p2: " << p2 << endl;delete[]p2;return 0;}

在这里插入图片描述

2、new和delete重载对象池应用在这里插入图片描述

在这里插入图片描述

#include<iostream>
using namespace std;/*运算符的重载:成员方法、全局方法
* 内存池 进程池 线程池 连接池 对象池
*/template<typename T>
class Queue
{
public:Queue(){_front = _rear = new QueueItem();}~Queue(){QueueItem* cur = _front;while (cur != nullptr){_front = _front->_next;delete cur;cur = _front;}}void push(const T& val){QueueItem* item = new QueueItem(val);_rear->_next = item;_rear = item;}void pop(){if (empty()){return;}QueueItem* first = _front->_next;_front->_next = first->_next;if (_front->_next == nullptr){_rear = _front;}delete first;}T front()const{return   _front->_next->_data;}bool empty() const { return _rear == _front; }
private:struct QueueItem //产生一个QueueItem的对象池(10000个节点){//给QueueItem提供自定义的内存管理QueueItem(T data = T()) :_data(data), _next(nullptr) {}void* operator new (size_t size){if (_itempool == nullptr){_itempool = (QueueItem*)new char[POOL_ITEM_SIZE * sizeof(QueueItem)]; //开辟内存QueueItem* p = _itempool;for (; p < _itempool + POOL_ITEM_SIZE - 1; ++p){p->_next = p + 1;}p->_next = nullptr;}QueueItem* p = _itempool;_itempool = _itempool->_next;return p;}void operator delete(void* ptr){QueueItem* p = (QueueItem*)ptr;p->_next = _itempool;_itempool = p;}T _data;QueueItem* _next;static const int POOL_ITEM_SIZE = 1000000;static QueueItem* _itempool; //指向头节点的指针};QueueItem* _front; //指向头节点QueueItem* _rear; //指向队尾
};template<typename T>
typename Queue<T>::QueueItem* Queue<T>::QueueItem::_itempool = nullptr;
int main()
{Queue<int> que;for (int i = 0; i < 10000; i++){que.push(i);que.pop();}cout << que.empty() << endl;return 0;
}

3、运算符重载 复数类

#include<iostream>
using namespace std;/*
* C++运算符重载:使得对象的运算表现得和内置类型一样
*///复数类
class CComplex
{
public:CComplex(int r = 0, int i = 0):mreal(r), mimage(i) {}//指导编译器如何做加法操作CComplex& operator+(const CComplex& comp){this->mimage += comp.mimage;this->mreal += comp.mreal;return *this;}CComplex& operator+(const int& b){this->mreal += b;return *this;}CComplex& operator++(){mreal += 1;mimage += 1;return *this;}CComplex& operator++(int){CComplex tmp = *this;this->mimage++;this->mreal++;return tmp;}friend CComplex& operator+(const int& a, CComplex& comp);friend ostream& operator<<(ostream& os, const CComplex& comp);void show() { cout << "real: " << mreal << " image: " << mimage << endl; }
private:int mreal;int mimage;
};CComplex& operator+(const int& a, CComplex& comp)
{comp.mreal += a;return comp;
}ostream& operator<<(ostream& os, const CComplex& comp)
{os << "real: " << comp.mreal << " image: " << comp.mimage << endl;return os;
}
int main()
{CComplex comp1(10, 10);CComplex comp2(20, 20);//CComplex comp3 = comp1 + comp2;CComplex comp3 = comp1.operator+(comp2);comp3.show();comp3.operator+(10);comp3.show();comp3 = 15 + comp3;comp3.show();CComplex comp4 = comp3++;  //operator++()前置++ operator++(int)后置++comp4.show();++comp4;comp4.show();cout << comp4 << endl;return 0;
}

4、string类的实现

#include<iostream>
using namespace std;
#include<string>
//自己实现string类
class String
{
public:String(const char* p = nullptr){if (p != nullptr){_str = new char[strlen(p) + 1];strcpy_s(_str, strlen(p) + 1, p);}else{_str = new char[1];*_str = '\0';}}~String(){delete[] _str;_str = nullptr;}String(const String& str){_str = new char[strlen(str._str) + 1];strcpy_s(_str, strlen(str._str) + 1, str._str);}String& operator=(const String& src){if (this == &src){return *this;}delete[]_str;_str = new char[strlen(src._str) + 1];strcpy_s(_str, strlen(src._str) + 1, src._str);return *this;}bool operator>(const String& str)const{return strcmp(_str, str._str) > 0;}bool operator<(const String& str)const{return strcmp(_str, str._str) < 0;}bool operator==(const String& str)const{return strcmp(_str, str._str) == 0;}char& operator[](int index){return _str[index];}char& operator[](int index)const{return _str[index];}int length()const { return strlen(_str); }const char* c_str() const { return _str; }friend String operator+(const String& lhs, const String& rhs);
public:ostream& operator<<(ostream& os){os << _str;return os;}private:char* _str;
};// 重载加法运算符
String operator+(const String& lhs, const String& rhs)
{String tmp;delete[] tmp._str;tmp._str = new char[strlen(lhs._str) + strlen(rhs._str) + 1];strcpy_s(tmp._str, strlen(lhs._str) + 1, lhs._str);strcat_s(tmp._str, strlen(lhs._str) + strlen(rhs._str) + 1, rhs._str);return tmp;
}
int main()
{String a("aaa");String b("ccc");a.operator<<(cout) << endl;(a + b).operator<<(cout) << endl;//string str1;//string str2 = "aaa";//string str3 = "bbbb";//string str4 = str2 + str3;//cout << str4 << endl;return 0;
}

5、迭代器

在这里插入图片描述

#include<iostream>
using namespace std;
#include<string>
//自己实现string类 以及迭代器
class String
{
public:String(const char* p = nullptr){if (p != nullptr){_str = new char[strlen(p) + 1];strcpy_s(_str, strlen(p) + 1, p);}else{_str = new char[1];*_str = '\0';}}~String(){delete[] _str;_str = nullptr;}String(const String& str){_str = new char[strlen(str._str) + 1];strcpy_s(_str, strlen(str._str) + 1, str._str);}String& operator=(const String& src){if (this == &src){return *this;}delete[]_str;_str = new char[strlen(src._str) + 1];strcpy_s(_str, strlen(src._str) + 1, src._str);return *this;}bool operator>(const String& str)const{return strcmp(_str, str._str) > 0;}bool operator<(const String& str)const{return strcmp(_str, str._str) < 0;}bool operator==(const String& str)const{return strcmp(_str, str._str) == 0;}char& operator[](int index){return _str[index];}char& operator[](int index)const{return _str[index];}int length()const { return strlen(_str); }const char* c_str() const { return _str; }friend String operator+(const String& lhs, const String& rhs);//提供迭代器class iterator{public:iterator(char* p = nullptr) :_p(p) {}bool operator!=(const iterator& it){return _p != it._p;}void  operator++(){++_p;}char& operator*() { return *_p; }private:char* _p;};iterator begin() { return iterator(_str); }iterator end() { return iterator(_str + length()); }
public:ostream& operator<<(ostream& os){os << _str;return os;}private:char* _str;
};// 重载加法运算符
String operator+(const String& lhs, const String& rhs)
{String tmp;delete[] tmp._str;tmp._str = new char[strlen(lhs._str) + strlen(rhs._str) + 1];strcpy_s(tmp._str, strlen(lhs._str) + 1, lhs._str);strcat_s(tmp._str, strlen(lhs._str) + strlen(rhs._str) + 1, rhs._str);return tmp;
}
int main()
{String s("hello world!");for (String::iterator it = s.begin(); it != s.end(); ++it){cout << *it << " ";}//c++11cout << endl;for (char ch : s){cout << ch << " ";}return 0;
}

6、Vector迭代器

#include<iostream>
using namespace std;/*
template <class _Ty,class _Alloc = allocator<_Ty>>class Vector容器的空间配置器allocator做四件事情 内存开辟 内存释放 对象构造 对象析构
*///定义容器的空间配置器,和c++标准库的allocator实现一样
template<typename T>
class Allocator
{
public:T* allocate(size_t size) //负责内存开辟{return (T*)malloc(sizeof(T) * size);}void deallocate(void* p) //负责内存释放{free(p);}void construct(T* p, const T& val) //负责对象构造{new (p) T(val);//定位new}void destroy(T* p)//负责对象析构{p->~T();//代表了T类型的析构函数}
};
template<typename T, typename Alloc = Allocator<T>>
class Vector
{
public:Vector(int size = 10){//需要把内存开辟和对象构造分开处理//_first = new T[size];_first = _allocator.allocate(size);_last = _first;_end = _first + size;}~Vector(){//delete[]_first;//析构有效的元素,然后释放_first指针指向的堆内存for (T* p = _first; p != _last; p++){_allocator.destroy(p); //把first指针指向的数组的有效元素进行析构操作}_allocator.deallocate(_first);//释放堆上的数组内存_first = _last = _end = nullptr;}Vector(const Vector<T>& rhs){int size = rhs._end - rhs._first;//_first = new T[size]; //空间大小_first = _allocator.allocate(size);int len = rhs._last - rhs._first;for (int i = 0; i < len; i++){//_first[i] = rhs._first[i];_allocator.construct(_first + i, rhs._first[i]);}_last = _first + len;_end = _first + size;}Vector<T>& operator=(const Vector<T>& rhs) //拷贝构造{if (this == &rhs)return *this;//delete[] _first;for (T* p = _first; p != _last; p++){_allocator.destroy(p); //把first指针指向的数组的有效元素进行析构操作}_allocator.deallocate(_first);//释放堆上的数组内存int size = rhs._end - rhs._first;int len = rhs._last - rhs._first;for (int i = 0; i < len; i++){//_first[i] = rhs._first[i];_allocator.construct(_first + i, rhs._first[i]);}_last = _first + len;_end = _first + size;return *this;}void push_back(const T& val){if (full()){expand();}//*_last = val;_allocator.construct(_last, val);_last++;}void pop_back(){if (empty()){return;}//--_last;--_last;_allocator.destroy(_last);}T back()const //返回容器末尾的元素值{return *(_last - 1);}bool full()const { return _last == _end; }bool empty()const { return _first == _last; }int size()const { 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 _ptr != it._ptr;}void operator++(){_ptr++;}T& operator*() { return *_ptr; } //解引用读取与赋值const T& operator*() const { return *_ptr; } //解引用读取与赋值private:T* _ptr;};//需要给容提供begin和end的方法iterator begin() { return iterator(_first); }iterator end() { return iterator(_last); }private:void expand(){int _size = _end - _first;//T* tmp = new T[_size * 2];T* tmp = _allocator.allocate(2 * _size);for (int i = 0; i < _size; i++){//tmp[i] = _first[i];_allocator.construct(tmp + i, _first[i]);}//delete[]_first;for (T* p = _first; p != _last; p++){_allocator.destroy(p);}_allocator.deallocate(_first);_first = tmp;_last = _first + _size;_end = _first + 2 * _size;}T* _first; //指向数组的起始的位置T* _last; //指向数组有效元素的后继位置T* _end; //指向数组空间的后继位置Alloc _allocator;//定义i容器中的空间配置项};
//容器空间分配器
class Test
{
public:Test() { cout << "test()" << endl; }~Test() { cout << "~test()" << endl; }Test(const Test&) { cout << "Test(const Test&)" << endl; }
};int main()
{Vector<int>vec;for (int i = 0; i < 20; i++){vec.push_back(rand() % 100 + 1);}Vector<int>::iterator it = vec.begin();for (; it != vec.end(); ++it){cout << *it << " ";}cout << endl;return 0;
}

在这里插入图片描述

7、迭代器失效:

#include<iostream>
#include<vector>
using namespace std;/*
迭代器的失效问题?
1、迭代器为什么会失效?
a、容器调用erase方法后,当前位置到容器末尾元素的所有迭代器全部失效了
b、容器调用insert后,当前位置到容器末尾元素的所有迭代器全部失效了迭代器依然有效 迭代器全部失效*/
int main()
{vector<int> vec;for (int i = 0; i < 20; i++){vec.push_back(rand() % 100 + 1);}for (int v : vec){cout << v << " ";}cout << endl;auto it = vec.begin();for (; it != vec.end(); it++){if (*it % 2 == 0){it = vec.insert(it, *it - 1);++it;}}for (int v : vec){cout << v << " ";}cout << endl;//给vec容器中所有的偶数前面添加一个小于偶数值1的数字//auto it = vec.begin();//for (; it != vec.end(); it++)//{//	if (*it % 2 == 0)//	{//		//这里的迭代器在第一次insert之后就失效了//		vec.insert(it, *it - 1);//		//it += 2;//		//break;//	}//}#if 0auto it = vec.begin();for (; it != vec.end(); it++){if (*it % 2 == 0){vec.erase(it); //迭代器失效的问题 第一次调用erase以后迭代器就失效了//break;}}
#endif return 0;}

在这里插入图片描述
下次学习vector迭代器失效的实现过程。

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

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

相关文章

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测 目录 回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现GA-LSSVM遗传算法优化最小…

Linux进程控制——Linux进程终止

前言&#xff1a;前面了解完前面的Linux进程基础概念后&#xff0c;我们算是解决了Linux进程中的一大麻烦&#xff0c;现在我们准备更深入的了解Linux进程——Linux进程控制&#xff01; 我们主要介绍的Linux进程控制内容包括&#xff1a;进程终止&#xff0c;进程等待与替换&a…

车载测试:为什么你投十份简历,只有一两家公司约你?

最根本的原因&#xff0c;就是一方在汲汲渴求&#xff0c;而恰恰另一方呈现出的关键点让其怦然心动。求者心中有所想&#xff0c;而应者恰恰展现了求者所想的那一面。这就是个中奥妙。 程序员在找工作时&#xff0c;在一开始有三件事情会对能否获得面试机会至关重要&#xff1…

计算机毕业设计springboot+vue高校教师职称评审评定系统605z3

技术栈 前端&#xff1a;vue.jsElementUI 开发工具&#xff1a;IDEA 或者eclipse都支持 编程语言: java 框架&#xff1a; ssm/springboot 数据库: mysql 版本不限 数据库工具&#xff1a;Navicat/SQLyog都可以 详细技术&#xff1a;javaspringbootvueMYSQLMAVEN 本系统采用in…

MySQL相关文件的介绍

其中的pid-file/var/run/mysqld/mysqld.pid是用来定义MySQL的进程ID的信息的&#xff0c; 这个ID是操作系统分配给MySQL服务进程的唯一标识&#xff0c;使得系统管理员可以轻松识别和管理该进程。 其中的log-error/var/log/mysqld.log是MySQL的错误日志文件&#xff0c;如果有…

Matlab-粒子群优化算法实现

文章目录 一、粒子群优化算法二、相关概念和流程图三、例题实现结果 一、粒子群优化算法 粒子群优化算法起源于鸟类觅食的经验&#xff0c;也就是一群鸟在一个大空间内随机寻找食物&#xff0c;目标是找到食物最多的地方。以下是几个条件: (1) 所有的鸟都会共享自己的位置以及…

2024中国(重庆)无人机展览会8月在重庆举办

2024中国(重庆)无人机展览会8月在重庆举办 邀请函 主办单位&#xff1a; 中国航空学会 重庆市南岸区人民政府 招商执行单位&#xff1a; 重庆港华展览有限公司 报名&#xff1a;【交易会I 59交易会2351交易会9466】 展会背景&#xff1a; 为更好的培养航空航天产业和无人…

【linux学习】多线程(1)

文章目录 线程的概念线程与进程 线程的用法线程的创建多线程 线程的等待线程锁死锁 线程的概念 在Linux中&#xff0c;线程&#xff08;Thread&#xff09;是程序执行流的最小单位&#xff0c;是进程中的一个实体&#xff0c;负责在程序中执行代码。线程本身不拥有系统资源&…

支持视频切片的开源物联网平台

软件介绍 MzMedia开源视频联动物联网平台是一个简单易用的系统,该平台支持主流短视频平台&#xff08;如抖音、快手、视频号&#xff09;的推流直播功能&#xff0c;同时提供视频切片等功能。系统后端采用Spring Boot&#xff0c;前端采用Vue3和Element Plus&#xff0c;消息服…

计算机毕业设计python校园二手交易系统aqj3i-

什么叫三层架构呢&#xff1f;指的是表示层、组件层、数据访问层。组件层是双层架构没有的&#xff0c;它的加入&#xff0c;把复杂的问题分解得更简单、明了&#xff0c;通过组件层&#xff0c;实现控制数据访问层&#xff0c;这样达到功能模块易于管理、易于访问等目的&#…

<MySQL> 数据库基础

目录 一、数据库概念 &#xff08;一&#xff09;什么是数据库 &#xff08;二&#xff09;数据库存储介质 &#xff08;三&#xff09;常见数据库 二、数据库基本操作 &#xff08;一&#xff09;连接数据库 &#xff08;二&#xff09;使用数据库 &#xff08;三&…

如何安全可控地进行内外网跨网络传输文件?

跨网络传输文件通常指的是在不同的网络环境之间移动数据&#xff0c;这在现代企业运营中非常常见。随着网络技术的高速发展&#xff0c;为了有效地保护内部的核心数据资产&#xff0c;企业一般会采用内外网隔离的策略。在进行内外网跨网络传输文件时&#xff0c;需要考虑多种因…

车载测试和传统测试有什么区别

搞清楚车载测试和传统应用测试的区别,就可以大胆冲冲冲! 车载测试随着市场的需求量增加又火来一波,一直’遥遥领先’的我们一定要告诉大家一个事实:车载测试和传统的应用测试是有很大区别的. 测试对象不一样 传统测试:测试的对象无非就是各种应用,比如电脑端的web系统(使用浏…

在Ubuntu 24.04 LTS (Noble Numbat)上安装nfs server以及nfs client

在Ubuntu 24.04 LTS (Noble Numbat)上,我使用的是最小化安装, 当然server版本的Ubuntu在安装的时候可能会有网络不通的问题,解决办法见如下文章: ubuntu 24.04 server 仅NAT模式上网设置静态IP设置-CSDN博客文章浏览阅读489次,点赞9次,收藏3次。在Ubuntu 24.04 上设置网…

3kCTF2021 echo klibrary

文章目录 前言echoklibrary 前言 今天状态不好&#xff0c;很多事情都不想干&#xff0c;就做一做简单的题目 echo 内核版本&#xff1a;v5.9.10smap/smep/kaslr 开启modprobe_path 可写 题目给了源码&#xff0c;非常简单就是无限次的任意地址读写&#xff1a; #include …

docker(四):数据卷

数据卷 卷的设计目的就是数据的持久化&#xff0c;完全独立于容器的生存周期&#xff0c;因此Docker不会在容器删除时删除其挂载的数据卷。 1、docker run docker run -it --privilegedtrue -v /宿主机绝对路径目录:/容器内目录 镜像名2、挂载注意事项 --privilegedtru…

YOLO数据集制作(二)|json文件转txt验证

以下教程用于验证转成YOLO使用的txt格式&#xff0c;适用场景&#xff1a;矩形框&#xff0c;配合json格式文件转成YOLO使用的txt格式脚本使用。 https://blog.csdn.net/StopAndGoyyy/article/details/138681454 使用方式&#xff1a;将img_path和label_path分别填入对应的图…

网络 | 应用层-websocket协议概述与握手过程解析

背景&#xff1a;这里为了实现消息实时传输决定引入websocket协议。 不管是发送消息还是接收消息&#xff0c;都需要实时传输&#xff0c;张三发给李四&#xff0c;李四立马就能收到&#xff0c;基于HTTP实现是有些困难的。 但轮询方式也带来了一些问题 1、消耗更多系统资源&…

Nacos 入门篇---内存注册表:高并发下如何保证注册表读写并发冲突 ?(五)

一、引言 本章来讲解Nacos注册表是如何进行写入数据的&#xff5e; 二、目录 目录 一、引言 二、目录 三、服务注册源码内容回顾 客户端源码回顾&#xff1a; 服务端源码回顾&#xff1a; 四、Nacos 注册表结构详解 五、写时复制概念 六、Nacos服务注册写入注册表源…

Lombok注解详解

文章目录 注解详解lombok包下注解汇总- Getter- Setter- ToString- EqualsAndHashCode- Data- Value- NonNull- NoArgsConstructor- AllArgsConstructor- RequiredArgsConstructor- Builder- Synchronized- Cleanup- Singular- Generated- SneakyThrows- val- var experimental…