运算符重载
1.定义
2.运算符重载机制的实现(通过函数实现)
class CInt
{
public:
CInt(int val)
:value(val){}
bool operator<(int rhs)//类中 _thiscall this
{
return value < rhs;
}
//前置++ 后置++
//标志
const CInt operator++(int)//后置++就是先做个备份,用临时量先存储起来(临时量是常量),因此const
{
CInt tmp(*this);//局部对象----》备份
value++;
return tmp;
}
CInt& operator++() //返回的就是本身,别名
{
++value;
return *this;
}
int& operator[](int* parr)
{
return parr[value];
}
private:
int value;
};
int main()
{
int arr[] = { 1, 32, 35, 43, 65, 8 };
int len = sizeof(arr) / sizeof(arr[0]);
for (CInt i = 0; i < len; i++)
{
std::cout << i[arr] << " ";
}
std::cout << std::endl;
return 0;
}
3.复数类
class CComplex//复数类
{
public:
CComplex(int real, int image)
:mreal(real), mimage(image)
{}
const CComplex operator+(int rhs) //放在临时量中,&不生成临时量
{
return CComplex(mreal + rhs, mimage);
}
friend const CComplex operator+(int, const CComplex&);
bool operator>(const CComplex& lhs)
{
return (mreal > lhs.mreal) || ((mreal == lhs.mreal) && (mimage > lhs.mimage));
}
bool operator==(const CComplex& rhs)
{
return (mreal == rhs.mreal) && (mimage == rhs.mimage);
}
friend std::istream& operator>>(std::istream&, CComplex&);
friend std::ostream& operator<<(std::ostream&, const CComplex&);
private:
int mreal;
int mimage;
};
//_cdecl
const CComplex operator+(int lhs, const CComplex& rhs) //cdcl调用约定,meiyouthis指针,左右操作数都要通过形参传递
{
return CComplex(lhs + rhs.mreal, rhs.mimage); //访问类内的私有成员变量,破坏了封装性,因此采用友元函数
}
std::ostream& operator<<(std::ostream& out, const CComplex& rhs)//输出流为什么用引用?
//一个程序分配一个输出缓冲区。cout绑定了一个输出缓冲区,如果out不是引用类型,就意味着需要两个缓冲区,所以out应该是&类型
{
out << rhs.mreal << "<==>" << rhs.mimage;
return out;
}
std::istream& operator>>(std::istream& in, CComplex& rhs)//rhs不是const类型,因为输入的cc2是变量
{
in >> rhs.mreal;
in >> rhs.mimage;
return in;
}
int main()
{
CComplex cc1(10, 20);
CComplex cc2 = cc1 + 10;//V
CComplex cc3 = 10 + cc1;//在类外实现,因为this指针指向的是对象所占的内存空间,所以指向的只能是cc1,对于此表达式顺序的合适,因此要在类外单独实现(叫全局的方法,cdcl调用约定)
if (cc2 > cc1)//V
{
std::cout << cc2 << std::endl; //把cc2流入cout中,当输出流关闭之后,把数值打印到屏幕上
}
if (cc3 == cc2)//V
{
std::cout << cc1 << std::endl;
}
std::cin >> cc2;
std::cout << cc2 << std::endl;
return 0;
}
4.String类
#include<iostream>
#pragma warning (disable:4996)
class String
{
public:
String(const char* ptr)
:mptr(new char[strlen(ptr)+1]())
{
strcpy_s(mptr, strlen(ptr) + 1, ptr);
}
String(const String& rhs)
{
mptr = new char[strlen(rhs.mptr) + 1]();
strcpy_s(mptr, strlen(rhs.mptr) + 1, rhs.mptr);
}
const String operator+(char* rhs)
{
char* tmp = new char[strlen(mptr) + strlen(rhs)+1]();
strcpy_s(tmp, strlen(mptr) + 1, mptr);
strcat(tmp, rhs);
String str(tmp);
delete[] tmp;
return str;
}
const String operator+(const String& rhs)
{
char* tmp = new char[strlen(rhs.mptr) + strlen(mptr) + 1]();
strcpy_s(tmp, strlen(mptr) + 1, mptr);
strcat(tmp,rhs.mptr);
String lhs(tmp);
delete[] tmp;
return lhs;
}
friend const String operator+(const char*, const String&);
bool operator<(const String& str)
{
return strcmp(mptr, str.mptr) < 0;
}
bool operator!=(const String& str)
{
return strcmp(mptr,str.mptr)!=0;
}
char& operator[](int index)//[]运算符重载函数
{
return mptr[index];
}
friend std::ostream& operator<<(std::ostream&, const String&);
friend std::ostream& operator>>(std::ostream&, const String&);
private:
char* mptr;
};
const String operator+(const char* str,const String& rhs)
{
char* tmp = new char[strlen(str) + strlen(rhs.mptr) + 1]();
strcpy_s(tmp, strlen(str) + 1, str);
strcat(tmp, rhs.mptr);
String lhs(tmp);
delete[] tmp;
return lhs;
}
std::ostream& operator<<(std::ostream& out, const String& str)
{
out << str.mptr << " ";
return out;
}
int main()
{
std::string str1("hello");
//std::string str2("world");
//std::cout << str1[0] << std::endl; //str是对象,不是指针,所以要写[]运算符重载函数
std::string::iterator it = str1.begin();//把it对象当作指针来使用
//面向对象的指针:以对象的形式存在,但是做的却是指针的事
while (it != str1.end())
{
std::cout << *it;//*it是对象的解引用,要实现一个解引用运算符重载函数
it++; //++就实现了getnext函数
}
// String str1("hello");
// String str2 = str1 + " world";//除了运算符重载+,还有一个深拷贝(拷贝构造),将值赋给str2
// String str3 = "hi " + str1;
// String str4 = str1 + str2;
// if (str1 < str2)
// {
// std::cout << str1 << std::endl;
// }
//std::cout << str2 << std::endl;测试用例
//std::cout << str3 << std::endl;
// if (str3 != str4)
// {
// std::cout << str4 << std::endl;
// }
return 0;
}
5.iterator迭代器
#include<iostream>
class String;
class Iterator
{
public:
Iterator(String* ps, int idx)
:pstr(ps),index(idx)
{}
bool operator!=(const Iterator rhs)
{
return index = rhs.index;
}
char& operator*();// 特殊,this指针接收右操作数(平时都是左边)
const Iterator operator++(int)//后置++
{
Iterator tmp(*this);
index++;
return tmp;
}
Iterator& operator++()
{
index++;
return *this;
}
private:
String* pstr;//指向String类型的对象
int index;//下标标识
};
#pragma warning (disable:4996)
class String
{
public:
typedef Iterator iterator;
String(char* ptr)
:mptr(new char[strlen(ptr)+1]())
{
strcpy_s(mptr, strlen(ptr) + 1, ptr);
}
String(const String& rhs)
{
mptr = new char[strlen(rhs.mptr) + 1]();
strcpy_s(mptr, strlen(rhs.mptr) + 1, rhs.mptr);
}
const String operator+(char* rhs)
{
char* tmp = new char[strlen(mptr) + strlen(rhs)+1]();
strcpy_s(tmp, strlen(mptr) + 1, mptr);
strcat(tmp, rhs);
String str(tmp);
delete[] tmp;
return str;
}
const String operator+(const String& rhs)
{
char* tmp = new char[strlen(rhs.mptr) + strlen(mptr) + 1]();
strcpy_s(tmp, strlen(mptr) + 1, mptr);
strcat(tmp,rhs.mptr);
String lhs(tmp);
delete[] tmp;
return lhs;
}
friend const String operator+(char*, const String&);
bool operator<(const String& str)
{
return strcmp(mptr, str.mptr) < 0;
}
bool operator!=(const String& str)
{
return strcmp(mptr,str.mptr)!=0;
}
char& operator[](int index)//[]运算符重载函数
{
return mptr[index];
}
iterator begin()
{
return iterator(this,0);
}
iterator end()
{
return iterator(this, strlen(mptr));
}
friend std::ostream& operator<<(std::ostream&, const String&);
friend std::ostream& operator>>(std::ostream&, const String&);
private:
char* mptr;
};
char& Iterator::operator*()//特殊,this指针接收右操作数(平时都是左边)
//返回的是指向的元素本身,指向的是字符
{
return (*pstr)[index];
//pstr解引用,就会变成对象,即(*pstr).operator[](index)
}
const String operator+(char* str,const String& rhs)
{
char* tmp = new char[strlen(str) + strlen(rhs.mptr) + 1]();
strcpy_s(tmp, strlen(str) + 1,str);
strcat(tmp, rhs.mptr);
String lhs(tmp);
delete[] tmp;
return lhs;
}
std::ostream& operator<<(std::ostream& out, const String& str)
{
out << str.mptr << " ";
return out;
}
int main()
{
std::string str1("hello");
//std::string str2("world");
//std::cout << str1[0] << std::endl; //str是对象,不是指针,所以要写[]运算符重载函数
std::string::iterator it = str1.begin();//把it对象当作指针来使用
//面向对象的指针:以对象的形式存在,但是做的却是指针的事
while (it != str1.end())
{
std::cout << *it;//*it是对象的解引用,要实现一个解引用运算符重载函数
it++; //++就实现了getnext函数
}
//String str1("hello");
//String str2 = str1 + " world";//除了运算符重载+,还有一个深拷贝(拷贝构造),将值赋给str2
//String str3 = "hi " + str1;
//String str4 = str1 + str2;
//if (str1 < str2)
//{
// std::cout << str1 << std::endl;
//}
std::cout << str2 << std::endl;
std::cout << str3 << std::endl;
//if (str3 != str4)
//{
// std::cout << str4 << std::endl;
//}
return 0;
}
通过指针,指向对象。通过标识迭代位置。
6.String类的写时拷贝
class String
{
public:
String(char* ptr)
{
mptr = new char[strlen(ptr) + 1 + 4]();//+4是计数器ref
mptr += 4;//指向数据域
strcpy_s(mptr, strlen(ptr) + 1, ptr);//把数据拷贝进去
getRef() = 1;
}
String(const String& rhs)//浅拷贝
{
mptr = rhs.mptr;
getRef()++;
}
String& operator=(const String& rhs)
{
if (this != &rhs)
{
--getRef();
if (getRef() == 0)
{
delete[] (mptr - 4);
}
mptr = rhs.mptr;
getRef()++;
}
return *this;
}
~String()
{
--getRef();
if (getRef() == 0)
{
delete[] (mptr - 4);//避免内存释放,先释放堆内存
}
mptr = NULL;
}
char& operator[](int index) //深拷贝
{
if (getRef() > 1)
{
char* tmp = new char[strlen(mptr) + 1 + 4]();
tmp += 4;
strcpy_s(tmp, strlen(mptr) + 1, mptr);
--getRef();
mptr = tmp;
getRef() = 1;
}
return mptr[index];
}
private:
int& getRef()//要修改并返回,因此类型用&,本身
{
return *(int*)(mptr - 4);//把char*类型转成int*类型,然后解引用
}
char* mptr;
};
int main()
{
String str1("hello");
String str2(str1);
String str3(str2);
String str4("world");
str2[0] = 'a';
return 0;
}
str的本质就是指向字符串的
A是一个赋值操作,B是修改操作
7.写时拷贝的缺陷
/*
设计点 :
operator[]
深拷贝
知不知道使用者使用operator[]做修改操作还是访问操作?
如果只是访问操作,采用深拷贝会造成内存浪费
*/
class String;
int main()
{
String str1("hello");
str1[0] = 'w';//修改 operator[]
std::cout << str1[0] << std::endl;//访问 operator[],如果只是访问操作,采用深拷贝会造成内存浪费
return 0;
}
8.内存自主管理机制
重载new和delete
/*
重载new和delete
void* malloc(size_t size);
void free(void* ptr);
*/
/*
new关键字
1.开辟内存 operator new 系统 允许重载
2.调用构造函数
delete关键字
1.调用析构函数
2.释放内存
*/
/* C语言中不允许重载,malloc和delete不能修改
void* malloc(size_t);
void free(void*);
*/
void* operator new(size_t size)
{
std::cout << "operator new!" << std::endl;
return malloc(size);
}
void operator delete(void* ptr)
{
std::cout << "operator delete!" << std::endl;
free(ptr);
}
int main()
{
int* p = new int(10);
*p = 20;
delete p;
return 0;
}
BSP:硬件资源(内存),由操作系统管理
内碎片:使用的空间小于开辟的空间,剩余的空间就是内碎片
9.内存池
池是什么意思?
资源的集合
池中申请,返还给池
资源的循环利用
#include<iostream>
template<typename T>
class Queue;
const int QueueItem_Count = 10;
template<typename T>
class QueueItem
{
public:
QueueItem(T val = T())
:mdata(val), pnext(NULL)
{}
void* operator new(size_t size)
{
if (pool == NULL)
{
pool = (QueueItem<T>*)new char[size * QueueItem_Count];
QueueItem<T>* pCur = pool;
for (pCur; pCur < pool + QueueItem_Count - 1;
pCur = pCur + 1)
{
pCur->pnext = pCur + 1;
}
pCur->pnext = NULL;
}
void* prt = pool; //已分配的需要剔除,不带头结点的头删
pool = pool->pnext;
return prt;
}
void operator delete(void* ptr)
{
QueueItem<T>* pqptr = (QueueItem<T>*)ptr;
pqptr->pnext = pool;
pool = pqptr;
}
private:
template<typename T>
friend class Queue;
T mdata;
QueueItem<T>* pnext;
static QueueItem<T>* pool;
};
template<typename T>
QueueItem<T>* QueueItem<T>::pool = NULL;
template<typename T>
class Queue
{
public:
Queue()
{
phead = ptail = new QueueItem<T>();
/*
1.operator new
*/
}
~Queue()
{
QueueItem<T>* pCur = phead;
QueueItem<T>* pNext;
while (pCur != NULL)
{
pNext = pCur->pnext;
delete pCur;
/*
1.调用析构函数
2.operator delete
*/
pCur = pNext;
}
phead = NULL;
}
void push(T val)
{
QueueItem<T>* pnewitem = new QueueItem<T>(val);
ptail->pnext = pnewitem;
ptail = ptail->pnext;
}
bool empty()
{
return (phead == ptail) && (phead != NULL);
}
void pop()
{
if (empty())
{
return;
}
QueueItem<T>* pCur = phead->pnext; //指向第一个节点
phead->pnext = pCur->pnext;
delete pCur;
}
T back()
{
if (empty())
{
throw std::exception("queu is empty!");
}
return ptail->mdata;
}
T front()
{
if (empty())
{
throw std::exception("queu is empty!");
}
return phead->pnext->mdata;
}
private:
QueueItem<T>* phead;
QueueItem<T>* ptail;
};
int main()
{
Queue<int> que;
for (int i = 0; i < 5; i++)
{
que.push(i + 1);// 2 3 4 5
}
que.pop();
auto qfront = que.front();
auto qback = que.back();
std::cout << "queue front: " << qfront << std::endl;
std::cout << "queue back: " << qback << std::endl;
return 0;
}
10.通用内存池
#include<iostream>
#include<string>
/*
内存池
*/
const int MEM_SIZE = 10;
template<typename T>
class MEM_Pool
{
public:
MEM_Pool()
{
pool = NULL;
}
void* Alloc(rsize_t size)
{
if (pool == NULL)
{
pool = (Node*)new char[(size + 4) * MEM_SIZE]();
Node* pCur = pool;
for (pCur; pCur < pool + MEM_SIZE - 1; pCur = pCur + 1)
{
pCur->pnext = pCur + 1;
}
pCur->pnext = NULL;
}
void* rt = pool;
pool = pool->pnext;
return rt;
}
void Dealloc(void* ptr)
{
Node* pptr = (Node*)ptr;
if (pptr == NULL)
{
return;
}
pptr->pnext = pool;
pool = pptr;
}
private:
class Node
{
public:
Node(T val)
:mdata(val), pnext(NULL)
{}
public:
T mdata;
Node* pnext;
};
Node* pool;
};
class Student
{
public:
Student(std::string name, std::string id, int age)
:mname(name), mid(id), mage(age)
{}
void* operator new(size_t size)
{
return mm.Alloc(size);
}
void operator delete(void* ptr)
{
mm.Dealloc(ptr);
}
private:
std::string mname;
std::string mid;
int mage;
static MEM_Pool<Student> mm;
};
MEM_Pool<Student> Student::mm;
/*
operator
*/
class CGoods
{
public:
CGoods(std::string name, float price, int amount)
:mname(name), mprice(price), mamount(amount)
{}
void* operator new(size_t size)
{
return mm.Alloc(size);
}
void operator delete(void* ptr)
{
mm.Dealloc(ptr);
}
private:
std::string mname;
float mprice;
int mamount;
static MEM_Pool<CGoods> mm; //所有学生共用一个内存池
};
MEM_Pool<CGoods> CGoods::mm;
int main()
{
Student* pstu1 = new Student("zhangsan", "001", 20);
Student* pstu2 = new Student("lisi", "002", 22);
delete pstu2;
return 0;
}
11.智能指针
以前:
堆内存只有地址没有名称的,而我们的操作是基于对象名来操作内存单元的,因此将堆的所有权交给栈上有名称的变量来进行管理。
现在:
将堆的所有权交给栈上的一个对象。
#include<iostream>
#include<string>
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* ptr):mptr(ptr)
{
std::cout << "SmartPtr::SmartPtr" << std::endl;
}
~SmartPtr()
{
std::cout << "SmartPtr::~SmartPtr" << std::endl;
delete mptr;
mptr = NULL;
}
//特殊,this接收的是右操作数
T& operator *()
{
return *mptr;
}
T* operator ->()
{
return mptr;
}
private:
T* mptr;
};
class Test
{
public:
Test(int a)
:ma(a)
{}
void Show()
{
std::cout << "ma:" << ma << std::endl;
}
public:
int ma;
};
int main()
{
/*
以前用对象访问:
int* p = new int;
*p = 20;
*/
Test* ptest = new Test(10);
ptest->ma;
ptest->Show();
SmartPtr<int> sp(new int);
*sp = 20;
SmartPtr<Test> sp2 ( new Test(20));
sp2->ma;
sp2->Show();
return 0;
}