1. 赋值运算符重载
- 编译器默认给类提供了一个默认的赋值运算符重载函数
- 默认的赋值运算符重载函数做了简单的赋值操作
- 当类有成员指针时,并且在构造函数中申请堆区空间,在析构函数中释放堆区空间,如果不重写赋值运算符重载函数,会导致内存泄漏,和同一块堆区空间被释放多次
- 赋值运算符中 为什么要返回引用 如果赋值运算符返回值,在复数运算时违背了它本来的寓意
class Maker1
{
public:
int id;
int age;
public:
void printMaker1()
{
cout << "id = " << this->id << " age = " << this->age << endl;
}
public:
Maker1()
{
}
Maker1(int id, int age)
{
this->id = id;
this->age = age;
}
};
void test01()
{
Maker1 m1(18, 20);
Maker1 m2;
m2 = m1; // 赋值操作 默认的赋值运算符重载函数做了简单的赋值操作
m2.printMaker1();
}
class Student
{
public:
char *pName;
public:
void printStudent()
{
cout << "name = " << this->pName << endl;
}
public:
Student(const char *name)
{
cout << "有参构造函数" << endl;
// 申请堆区空间
this->pName = new char[strlen(name) + 1];
// 拷贝数据
strcpy(this->pName, name);
}
// 防止浅拷贝
Student(const Student &m)
{
cout << "拷贝构造函数" << endl;
// 申请堆区空间
pName = new char[strlen(m.pName) + 1];
// 拷贝数据
strcpy(pName, m.pName);
}
// 重写赋值运算符重载
// 返回引用
Student &operator=(const Student &stu)
{
cout << "赋值运算" << endl;
// 不能确定this->pName指向的空间是否能装上stu中的数据,所以先释放this->pName指向的空间,再申请空间,拷贝数据,最后返回*this
// 1.删除原来的空间
if (this->pName != NULL)
{
delete[] this->pName;
this->pName = NULL;
}
// 2.申请空间
this->pName = new char[strlen(stu.pName) + 1];
// 3.拷贝数据
strcpy(this->pName, stu.pName);
// 4.返回对象本身
return *this;
}
~Student()
{
cout << "析构函数" << endl;
if (pName != NULL)
{
delete[] pName;
pName = NULL;
}
}
};
void test02()
{
Student m1("Emily");
Student m2 = m1; // 拷贝构造
m2.printStudent();
cout << "============== 1" << endl;
Student m3("悟空");
m3 = m1; // 赋值元算符
m3.printStudent();
cout << "============== 2" << endl;
Student m4 = m3 = m1;
m3.printStudent();
cout << "------------- 3" << endl;
}
为什么operator=返回一个reference to *this ?
为了实现连续赋值,赋值操作符必须返回一个引用指向操作符的左侧实参。这是你为class实现赋值操作符必须遵循的协议。这个协议不仅适用于标准的赋值形式,也适用于+=、-=、*=等等。
2. 关系运算符重载 == !=
// == !=
class Maker
{
private:
int id;
int age;
public:
Maker(int id, int age);
bool operator==(Maker &m2);
bool operator!=(Maker &m2);
};
Maker::Maker(int id, int age)
{
this->id = id;
this->age = age;
}
bool Maker::operator==(Maker &m2)
{
if (this->id == m2.id && this->age == m2.age)
{
return true;
}
else
{
return false;
}
}
bool Maker::operator!=(Maker &m2)
{
if (this->id != m2.id || this->age != m2.age)
{
return true;
}
else
{
return false;
}
}
void test01()
{
Maker m1(18, 20);
Maker m2(25, 56);
if (m1 == m2)
{
cout << "真" << endl;
}
else
{
cout << "假" << endl;
}
if (m1 != m2)
{
cout << "真" << endl;
}
else
{
cout << "假" << endl;
}
}
3. 前置加加和后置加加运算符重载
class Maker
{
public:
int age;
public:
Maker(int age)
{
this->age = age;
}
// 前置加加
Maker &operator++()
{
cout << "前置加加" << endl;
++this->age;
return *this;
}
// 后置加加
// 前置加加和后置加加以是否有占位符区分
Maker operator++(int) // 占位参数必须是int
{
// 后置加加 先返回 再加加
cout << "后置加加" << endl;
Maker tmp(*this); // 拷贝构造
++this->age;
return tmp;
}
};
// << 运算符重载
// 注意 此处 形参Maker m,如果使用引用,cout << m1++ << endl 会出错
// 原因 m1++ 后置加加是返回了一个临时对象,临时对象引用会出错
ostream &operator<<(ostream &os, Maker m)
{
cout << m.age << endl;
return os;
}
void test01()
{
Maker m1(1);
cout << m1 << endl; // 1
cout << ++m1 << endl; // 2
cout << (m1++).age << endl; // 2
cout << m1++ << endl; // 3
cout << m1 << endl; // 4
}
4. 数组下标运算符重载[]
class MyArray
{
public:
// 头插
void PushFront(int val)
{
if (mCapacity == mSize)
{
return;
}
// 数据往后移
for (int i = mSize - 1; i >= 0; I--)
{
pArray[i + 1] = pArray[I];
}
pArray[0] = val;
mSize++;
}
// 尾插
void PushBack(int val)
{
if (mCapacity == mSize)
{
return;
}
pArray[mSize] = val;
mSize++;
}
// 头删
void popFront()
{
if (mSize == 0)
{
return;
}
// 后面的数往前面移动来覆盖第一个元素
for (int i = 0; i < mSize - 1; I++)
{
pArray[i] = pArray[i + 1];
}
mSize--;
}
// 尾删
void popBack()
{
if (mSize == 0)
{
return;
}
mSize--;
}
// 获取数组元素的个数
int Size()
{
return mSize;
}
// 获取数组的容量
int Capacity()
{
return mCapacity;
}
// 指定位置插入元素
void Insert(int pos, int val)
{
if (mCapacity == mSize)
{
return;
}
if (pos < 0 || pos > mSize - 1)
{
return;
}
for (int i = mSize - 1; i >= pos; I--)
{
pArray[i + 1] = pArray[I];
}
pArray[pos] = val;
mSize++;
}
// 获取指定位置的值
int &Get(int pos)
{
if (pos >= 0 && pos <= mSize - 1)
{
return pArray[pos];
}
}
// 在指定位置修改值
void Set(int pos, int val)
{
if (pos < 0 || pos > mSize - 1)
{
return;
}
pArray[pos] = val;
}
public:
MyArray()
{
// 无参数构造
mCapacity = 20;
mSize = 0;
pArray = new int[mCapacity];
}
MyArray(int capacity, int val = 0)
{
mCapacity = capacity;
mSize = capacity;
pArray = new int[mCapacity];
for (int i = 0; i < mSize; I++)
{
pArray[i] = val;
}
}
MyArray(const MyArray &m)
{
mSize = m.mSize;
mCapacity = m.mCapacity;
// 申请空间
pArray = new int[mCapacity];
// 拷贝数据
for (int i = 0; i < mSize; I++)
{
pArray[i] = m.pArray[I];
}
}
// 重写赋值运算符重载函数
MyArray &operator=(const MyArray &m)
{
// 1. 删除原来空间
if (this->pArray != NULL)
{
delete[] pArray;
pArray = NULL;
}
this->mCapacity = m.mCapacity;
this->mSize = m.mSize;
// 2. 申请堆区空间
this->pArray = new int[this->mCapacity];
// 3.拷贝数据
for (int i = 0; i < this->mSize; I++)
{
this->pArray[i] = m.pArray[I];
}
// 4.返回对象本身
return *this;
}
// 数组下标运算符重载
int &operator[](int pos)
{
// 赋值时 mSize加加
if (this->mSize <= pos){
this->mSize ++;
}
return this->pArray[pos];
}
~MyArray()
{
if (pArray != NULL)
{
delete[] pArray;
pArray = NULL;
}
}
private:
int mCapacity; // 容量
int mSize; // 元素个数
int *pArray; // 指向堆区空间,存储数据
};
void test01()
{
MyArray arr;
for (int i = 0; i < 20; I++)
{
arr[i] = i + 10;
}
for (int i = 0; i < 20; I++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void test02()
{
MyArray arr;
for (int i = 0; i < 20; I++)
{
arr[i] = i + 10;
}
MyArray arr2; //无参构造
arr2 = arr; // 赋值运算
for (int i = 0; i < 20; I++)
{
cout << arr2[i] << " ";
}
cout << endl;
}
5. 指针运算符(*、->)重载
class Person{
public:
Person(int param){
this->mParam = param;
}
void PrintPerson(){
cout << "Param:" << mParam << endl;
}
private:
int mParam;
};
class SmartPointer{
public:
SmartPointer(Person* person){
this->pPerson = person;
}
//重载指针的->、*操作符
Person* operator->(){
return pPerson;
}
Person& operator*(){
return *pPerson;
}
~SmartPointer(){
if (pPerson != NULL){
delete pPerson;
}
}
public:
Person* pPerson;
};
void test01(){
//Person* person = new Person(100);
//如果忘记释放,那么就会造成内存泄漏
SmartPointer pointer(new Person(100));
pointer->PrintPerson();
}
// 智能指针类是管理另一个类的对象的释放
class Maker
{
public:
Maker()
{
cout << "Maker 无参构造" << endl;
}
void printMaker()
{
cout << "Hello Maker" << endl;
}
~Maker()
{
cout << "Maker 析构函数" << endl;
}
};
class SmartPoint
{
private:
Maker *pMaker;
public:
// ->指针运算符重载
Maker* operator->() {
return this->pMaker;
}
// *星花运算符重载
Maker& operator*() {
return *(this->pMaker);
}
public:
SmartPoint(Maker *m)
{
cout << "SmartPoint 有参构造函数" << endl;
pMaker = m;
};
~SmartPoint()
{
cout << "SmartPoint 析构函数" << endl;
if (this->pMaker != NULL)
{
delete this->pMaker;
this->pMaker = NULL;
}
};
};
void test01()
{
Maker *p = new Maker;
SmartPoint sm(p); // 栈区,test01()函数执行完后,会调用SmartPoint的析构函数
// 当test01()函数结束时,会调用SmartPoint的析构函数,在这个析构函数中delete了Maker的对象,就会调用Maker的析构函数
// (sm->)->printMaker() 编译器优化了
// sm-> 类似于 pMaker->
sm->printMaker();
(*sm).printMaker();
}
6. 函数调用符号() 重载(仿函数)
如果一个类重载了函数调用符号,那么这个类实例化出来的对象也叫仿函数
仿函数的作用: 1. 方便代码维护 2.方便有权限的调用函数 3. 作为算法的策略
// 重载函数调用符号
// 如果一个类重载了函数调用符号,那么这个类实例化出来的对象也叫仿函数
// 仿函数的作用: 1. 方便代码维护 2.方便有权限的调用函数 3. 作为算法的策略(后讲)
class Maker
{
public:
string name;
public:
// 第一个括号是表示我们要重载函数调用符号,第二个符号表示这是个函数
void operator()()
{
cout << "Hello Maker" << endl;
}
void operator()(int val1,int val2){
cout << val1 + val2 << endl;
}
void printMaker()
{
cout << name + "你好漂亮" << endl;
}
public:
Maker()
{
cout << "无参构造函数" << endl;
name = "Emily";
}
};
void test01()
{
Maker m; // 无参构造 m是对象
m(); // 看起来像函数,其实m是对象 void operator()()
m(10,20); // 调用的是函数调用符号重载函数 void operator()(int val1,int val2)
m.printMaker();
}
7. bool 和 ! 运算符重载
class Maker
{
private:
int a;
public:
void SetA(int a)
{
this->a = a;
}
// 重载bool运算符符
// 无返回值 无void
operator bool()
{
if (a > 0)
{
return true;
}
else
{
return false;
}
}
// 重载!运算符
bool operator!()
{
if (a > 0)
{
return false;
}
else
{
return true;
}
}
// 重载类型(int)运算符
// 无返回值
operator int() {
return 10;
}
public:
Maker()
{
a = 0;
};
~Maker(){
};
};
void test01()
{
Maker m;
m.SetA(10);
if (m)
{
cout << "真" << endl;
}
else
{
cout << "假" << endl;
}
if (!m)
{
cout << "真" << endl;
}
else
{
cout << "假" << endl;
}
int b = (int)m;
cout << b << endl;
}
8. 运算符和结合性
image.png image.png image.png image.png9. 强化训练-字符串的封装
MyString.h
#pragma once
#include <iostream>
using namespace std;
class MyString
{
friend ostream &operator<<(ostream &os, MyString &str);
friend istream &operator>>(istream &is, MyString &str);
public:
MyString();
MyString(int n, char c = 'a'); // 用户可以设定初始化字符串,n个c组成的字符串
MyString(const MyString &str);
MyString &operator=(const MyString &str);
MyString operator+(const MyString &str);
MyString operator+(const char *s);
MyString &operator+=(const MyString &str);
MyString &operator+=(const char *s);
char &operator[](int index);
int Size();
~MyString();
private:
char *pStr; // 指向堆区空间
int mSize;
};
ostream &operator<<(ostream &os, MyString &str);
istream &operator>>(istream &is, MyString &str);
MyString.cpp
#include "MyString.h"
MyString::MyString()
{
cout << "无参构造函数" << endl;
this->pStr = new char[1];
this->pStr[0] = '\0';
this->mSize = 0;
}
MyString::MyString(int n, char c)
{
cout << "有参构造函数" << endl;
this->pStr = new char[n + 1];
for (int i = 0; i < n; i++)
{
this->pStr[i] = c;
}
// 结束字符'\0'
// 防止被烫着
this->pStr[n] = '\0';
this->mSize = n;
}
MyString::MyString(const MyString &str)
{
cout << "拷贝构造函数" << endl;
this->pStr = new char[strlen(str.pStr) + 1];
strcpy(this->pStr, str.pStr);
this->mSize = str.mSize;
}
MyString &MyString::operator=(const MyString &str)
{
cout << "运算符重载 =" << endl;
// 1.释放原来空间
if (this->pStr != NULL)
{
delete[] this->pStr;
this->pStr = NULL;
}
// 2.申请空间
this->pStr = new char[strlen(str.pStr) + 1];
// 3.拷贝数据
strcpy(this->pStr, str.pStr);
this->mSize = str.mSize;
// 返回对象本身
return *this;
}
MyString MyString::operator+(const MyString &str)
{
cout << "运算符重载 + MyString" << endl;
// MyString s3=s1+s2
// 获取s3要开辟的空间大小
int newlen = this->mSize + str.mSize + 1;
// 1.定义一个临时变量
MyString tmp;
// 2.释放原来空间
if (tmp.pStr != NULL)
{
delete[] tmp.pStr;
tmp.pStr = NULL;
}
// 3.申请新的空间
tmp.pStr = new char[newlen];
// 清除下空间
memset(tmp.pStr, 0, newlen);
tmp.mSize = this->mSize + str.mSize;
// 4.追加字符到空间中
strcat(tmp.pStr, this->pStr);
strcat(tmp.pStr, str.pStr);
// 5. 返回临时变量
return tmp;
}
MyString MyString::operator+(const char *s)
{
cout << "运算符重载 + Char" << endl;
int newlen = this->mSize + strlen(s);
// 开辟空间
char *newspace = new char[newlen + 1];
memset(newspace, 0, newlen + 1);
// 追加数据到空间
strcat(newspace, this->pStr);
strcat(newspace, s);
MyString tmp;
if (tmp.pStr != NULL)
{
delete[] tmp.pStr;
tmp.pStr = NULL;
}
tmp.pStr = newspace;
tmp.mSize = newlen;
return tmp;
}
MyString &MyString::operator+=(const MyString &str)
{
cout << "运算符重载 += MyString" << endl;
int newlen = this->mSize + strlen(str.pStr);
// 1.开辟空间
char * newspace = new char[newlen + 1];
memset(newspace,0, newlen+1);
// 2.追加数据
strcat(newspace, this->pStr);
strcat(newspace, str.pStr);
// 3.释放原来空间
if (this->pStr != NULL)
{
delete[] this->pStr;
this->pStr = NULL;
}
// 4.指向newspace
this->pStr = newspace;
this->mSize = newlen;
return *this;
}
MyString &MyString::operator+=(const char *s)
{
cout << "运算符重载 += Char" << endl;
int newlen = this->mSize + strlen(s);
char *newspace = new char[newlen + 1];
memset(newspace, 0, newlen+1);
strcat(newspace, this->pStr);
strcat(newspace, s);
if (this->pStr != NULL)
{
delete[] this->pStr;
this->pStr = NULL;
}
this->pStr = newspace;
this->mSize = newlen;
return *this;
}
char &MyString::operator[](int index)
{
return this->pStr[index];
}
int MyString::Size()
{
return mSize;
}
MyString::~MyString()
{
if (this->pStr != NULL)
{
delete[] this->pStr;
this->pStr = NULL;
}
}
ostream &operator<<(ostream &os, MyString &str)
{
os << str.pStr;
return os;
}
istream &operator>>(istream &is, MyString &str)
{
// 1. 定义临时空间
char tmp[1024] = {0};
// 2.获取用户输入的信息
is>>tmp;
// 3.释放原来空间
if (str.pStr != NULL)
{
delete[] str.pStr;
str.pStr = NULL;
}
// 4.申请新的空间
str.pStr = new char[strlen(tmp) + 1];
memset(str.pStr,0, strlen(tmp)+1);
// 5.拷贝用户输入的信息
strcpy(str.pStr,tmp);
str.mSize = strlen(tmp);
return is;
}
网友评论