IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++运算符重载 -> 正文阅读

[C++知识库]C++运算符重载

一、学习复数类CComplex

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

注意:编译器做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法),如果没有成员方法,就在全局作用域找合适的运算符重载函数

代码:

#include<iostream>
using namespace std;


class CComplex
{
public:
	CComplex(int r = 0,int i=0)
		:mreal(r),mimage(i){}
	//指导编译器怎么做CComplex类对象的加法操作
	CComplex operator+(const CComplex& src)
	{
		/*
		CComplex tmp;
		tmp.mreal = this->mreal + src.mreal;
		tmp.mimage = this->mimage + src.mimage;
		return tmp;
		*/
		return CComplex(mreal + src.mreal, mimage + src.mimage);
	}
	CComplex operator++()
	{
		/*
		CComplex comp;
		mreal += 1;
		mimage += 1;
		return comp;
		*/
		return CComplex(++mreal, ++mimage);
	}
	CComplex operator++(int)
	{	
		mreal += 1;
		mimage += 1;
		return *this;
	}
	void operator+=(const CComplex& src)
	{
		mreal += src.mreal;
		mimage += src.mimage;
	}
	void show()
	{
		cout << "mreal:" << mreal << "  mimage:" << mimage << endl;
	}
private:
	int mreal;
	int mimage;
	friend CComplex operator+(const CComplex& lhs, const CComplex& rhs);
	friend ostream& operator<<(ostream& out, const CComplex& src);
	friend istream& operator>>(istream& in, CComplex& src);
};
CComplex operator+(const CComplex& lhs, const CComplex& rhs)
{
	return CComplex(lhs.mreal + rhs.mreal, lhs.mimage + rhs.mimage);
}

ostream& operator<<(ostream& out, const CComplex& src)
{
	out << "mreal:" << src.mreal << " mimage:" << src.mimage << endl;
	return out;
}
istream& operator>>(istream& in, CComplex& src)
{
	in >> src.mreal >> src.mimage;
	return in;
}
int main()
{
	CComplex comp1(10, 10);
	CComplex comp2(20, 20);

	//comp1.operator+(comp2)加法运算符的重载函数
	CComplex comp3 = comp1 + comp2;
	comp3.show();
	CComplex comp4 = comp1 + 20;
	comp4.show();
	//编译器做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法)
	//如果没有成员方法,就在全局作用域找合适的运算符重载函数
	CComplex comp5 = 30 + comp1;
	comp5.show();

	cout << "-----------------------------" << endl;
	//++ --单目运算符
	//operator()前置++;operator(int)后置++
	 
	//CComplex operator++(int)
	comp5 = comp1++;
	comp1.show();
	comp5.show();

	comp5 = ++comp1;
	comp1.show();
	comp5.show();

	cout << "-----------------------------" << endl;
	//void comp1.operator+=(comp2)		::operator+=(comp1,comp2)
	comp1 += comp2;
	comp1.show();//对象的输出
	
	cout << "-----------------------------" << endl;
	cin >> comp1 >> comp2;
	//cout::operator<<(cout,comp1)
	//ostream& operator<<(ostream& cout,const CComplex& src)
	cout << comp1 << comp2 << endl;

	return 0;
}


运行结果:
在这里插入图片描述

二、模拟实现C++的string类代码

#include<iostream>
//#include<string>
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(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)
	{
		return strcmp(_pstr, src._pstr) > 0;
	}
	bool operator<(const String& src)
	{
		return strcmp(_pstr, src._pstr) < 0;
	}
	bool operator==(const String& src)
	{
		return strcmp(_pstr, src._pstr) == 0;
	}
	~String()
	{
		delete[]_pstr;
		_pstr = nullptr;
	}
	int length() { return strlen(_pstr); }
	const char* c_str()const { return _pstr; }
	char& operator[](int index) { return _pstr[index]; }
	const char& operator[](int index)const { return _pstr[index]; }
private:
	char* _pstr;
	friend ostream& operator<<(ostream& out, const String& str);
	friend String operator+(const String& lhs, const String& rhs);
};
String operator+(const String& lhs, const String& rhs)
{
	char* ptmp = new char(strlen(lhs._pstr) + strlen(rhs._pstr) + 1);
	strcpy(ptmp, lhs._pstr);
	strcat(ptmp, rhs._pstr);
	return String(ptmp);
}
ostream& operator<<(ostream& out, const String& str)
{
	out << str._pstr;
	return out;
}
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;

	//string->char*
	char buf[1024] = { 0 };
	strcpy(buf, str6.c_str());
	return 0;
}

在这里插入图片描述

三、string字符串对象的迭代器iterator的实现

在这里插入图片描述

#include<iostream>
//#include<string>
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(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;
	}
	~String()
	{
		delete[]_pstr;
		_pstr = nullptr;
	}
	int length()const { return strlen(_pstr); }
	const char* c_str()const { return _pstr; }
	char& operator[](int index) { return _pstr[index]; }
	const char& operator[](int index)const { return _pstr[index]; }
	
	//给String字符串类型提供迭代器的实现
	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;
	};
	//begin返回的是容器底层首元素的迭代器的表示
	iterator begin() { return iterator(_pstr); }
	//end返回的是容器末尾元素的后继位置的迭代器的表示
	iterator end() {return iterator(_pstr + length());}
private:
	char* _pstr;
	friend ostream& operator<<(ostream& out, const String& str);
	friend String operator+(const String& lhs, const String& rhs);
};
String operator+(const String& lhs, const String& rhs)
{
	//char* ptmp = new char(strlen(lhs._pstr) + strlen(rhs._pstr) + 1);
	//strcpy(ptmp, lhs._pstr);
	//strcat(ptmp, rhs._pstr);
	//String tmp(ptmp);
	//delete[]ptmp;
	String tmp;
	tmp._pstr = new char(strlen(lhs._pstr) + strlen(rhs._pstr) + 1);
	strcpy(tmp._pstr, lhs._pstr);
	strcat(tmp._pstr, rhs._pstr);
	return tmp;
}
ostream& operator<<(ostream& out, const String& str)
{
	out << str._pstr;
	return out;
}
int main()
{
	//迭代器的功能:提供一种统一的方式,来透明的遍历容器
	String str1 = "hello world!";//str1叫容器吗?底层放了一组char类型的字符
	//容器的迭代器类型
	String::iterator it = str1.begin();
	for (; it != str1.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

	//C++11 foreach的方式来遍历容器的内部元素的值,其底层还是通过迭代器遍历
	for (char ch : str1)
	{
		cout << ch << " ";
	}
	cout << endl;
#if 0
	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;

	//string->char*
	char buf[1024] = { 0 };
	strcpy(buf, str6.c_str());
#endif // 0
	return 0;
}

在这里插入图片描述

四、vector容器的迭代器iterator实现

#include <iostream>
using namespace std;

template<typename T>
class vector
{
public:
    vector(int size = 10)
    {
        _first = new T[size];
        _last = _first;
        _end = _first + size;
    }
    ~vector()
    {
        delete[]_first;
        _first = _last = _end = nullptr;
    }
    vector(const vector<T>& rhs)
    {
        int size = rhs._end - rhs._first;
        _first = new T[size];
        int len = rhs._last - rhs._first;
        for (int i = 0; i < len; i++)
        {
            _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;
        int size = rhs._end - rhs._first;
        _first = new T[size];
        int len = rhs._last - rhs._first;
        for (int i = 0; i < len; i++)
        {
            _first[i] = rhs._first[i];
        }
        _last = _first + len;
        _end = _first + size;
    }
    void push_back(const T& val)//向容器末尾添加元素
    {
        if (full())
            expand();
        *_last++ = val;
    }
    void pop_back()//从容器末尾删除元素
    {
        if (empty())
            return;
        _last--;
    }
    T back()const//返回容器末尾元素的值
    {

        return *(_last - 1);
    }
    bool full() { return _last == _end; }
    bool empty() { 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 _ptr != it._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;//指向数组空间的后继位置
    void expand()
    {
        int size = _end - _first;
        T* ptmp = new T[size * 2];
        for (int i = 0; i < size; i++)
        {
            ptmp[i] = _first[i];
        }
        delete[]_first;
        _first = ptmp;
        _last = _first + size;
        _end = _first + size * 2;
    }
};
int main()
{
    vector<int> vec;
    for (int i = 0; i < 20; i++)
    {
        vec.push_back(rand() % 100 + 1);
    }

    int size = vec.size();
    for (int i = 0; i < size; ++i)
    {
        cout << vec[i] << " ";
    }
    cout << endl;

    vector<int>::iterator it = vec.begin();
    for (; it != vec.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    for (int val : vec)
    {
        cout << val << " ";
    }
    cout << endl;
    return 0;
}

在这里插入图片描述

五、容器的迭代器失效问题

在这里插入图片描述
1.迭代器为什么会失效?

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

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

c:insert来说,如果引起容器内存扩容,原来容器的所有的迭代器就全部失效了

2.迭代器失效后,问题该怎么解决?

对插入/删除点的迭代器进行更新操作

#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);
		
	}
	for (int v : vec)
	{
		cout << v << " ";
	}
	cout << endl;
#if 1



	//给vec容器中所有的偶数前面添加一个小于偶数值1的数字
	auto it = vec.begin();
	for (; it != vec.end(); ++it)
	{
		if (*it % 2 == 0)
		{
			//迭代器失效问题,第一次调用insert后,迭代器就失效了
			it = vec.insert(it, *it - 1);
			++it;
			//break;
		}
	}

#endif // 0
#if 0
	//把vec容器中所有的偶数全部删除
	auto it = vec.begin();
	while(it != vec.end())
	{
		if (*it % 2 == 0)
		{
			//迭代器失效问题,第一次调用erase后,迭代器就失效了
			it=vec.erase(it);
			//break;
		}
		else
		{
			++it;
		}
	}
#endif // 0
	for (int v : vec)
	{
		cout << v << " ";
	}
	cout << endl;
	return 0;
}

六、new和delete的原理

1、malloc和new的区别

  • malloc按字节开辟内存的;new开辟内存时需要指定类型 new int[10],所以malloc开辟内存返回的是void* operator new->int*
  • malloc只负责开辟空间,new不仅仅有malloc的功能,还可以进行数据初始化
  • malloc开辟内存失败返回nullptr指针;new抛出的是bad_alloc类型的异常

2、free和delete的区别

delete (int*)p:调用析构函数,再free§

#include<iostream>
using namespace std;

//先调用operator new开辟内存空间,然后调用对象的构造函数
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);
}

void* operator new[](size_t size)
{
	void* p = malloc(size);
	if (p == nullptr)
		throw bad_alloc();
	cout << "operator new[] addr:" << p << endl;
	return p;
}
void operator delete[](void* ptr)
{
	cout << "operator delete[] addr:" << ptr << endl;
	free(ptr);
}
int main()
{
	try
	{
		int* p = new int;
		delete p;

		int* q = new int[5];
		delete[]q;
	}
	catch (const bad_alloc& err)
	{
		cerr << err.what() << endl;
	}
	
	return 0;
}

在这里插入图片描述
3、new和delete能混用吗?C++为什么区分单个元素和数组的内存分配和释放呢?

正常搭配:new/delete;new[]/delete[]

对于普通的编译器内置类型 new/delete[];new[]/delete也可以;

自定义的类类型,有析构函数,为了调用正确的析构函数,那么开辟对象数组的时候,会多开辟4个字节,记录对象的个数。这时候不能混用!

在这里插入图片描述

七、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 _front == _rear; }
private:
	struct QueueItem//产生一个QueueItem的对象池
	{
		QueueItem(T data = T()) :_data(data), _next(nullptr) {};
		//给QueueItem提供自定义内存管理
		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 QueueItem* _itemPool;
		static const int POOL_ITEM_SIZE = 100000;
	};
	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 < 1000000; i++)
	{
		que.push(i);
		que.pop();
	}
	cout << que.empty() << endl;
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:10:21  更:2021-08-21 15:13:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:18:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计