算数运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
加号运算符
通过自己写函数,实现两个对象相加属性后返回新的对象
两种方式重载
成员函数方式重载 全局函数重载
上来 person p3 = p2+p1 会报错 ,没有这种运算
成员函数重载写在类的里面
person operator+(person &p)
{
person temp;
temp.m_a =this->m_a+ p.m_a;
}
这里的 引用相当于就是传入的哪个person
void func(int& ref)
//发现是引用,转换为 int* const ref = &a; 地址
ref = 100; // ref是引用,转换为*ref = 100
Person p1(10, 10);
Person p2(20, 20);
本质上为 person p3 = p1.operator+(p2);
简化为person p3 = p2+p1。
//运算符重载 可以发生函数重载
Person p4 = p3 + 10; //相当于 p4 = operator+(p3,10)
总结1:对于内置的数据类型的表达式的的运算符是不可能改变的 1+1 = 2 无法改变
总结2:不要滥用运算符重载
左移运算符
这不是想要的结果
通常不会用成员函数重载<<运算符,因为无法实现cout在左侧
只能用全局函数实现
//ostream对象只能有一个
本质 operator<<(cout,p) 简化为 cout<<p
标准输出流对象 ,通过标准输出流这个类
cout全局只有一个 必须以引用的对象出现
ostream& operator<<(ostream& out, Person& p) {out << "a:" << p.m_A << " b:" << p.m_B;return out;
}
注意返回值 如果返回值是一个void
那么只能 cout<<p
如果 cout<<p<<endl 会报错
注意链式编程思想,返回还是一个cout得话就可以继续往后追加
cout属于标准输出流对象 ostream& 引用的方式返回
引用本质是取别名 cout名字随便取
如果对象属性设置为私有,可以用友员的方式
friend ostream& operator<<(ostream& out, Person& p);
总结:重载左移运算符配合友元可以实现输出自定义数据类型
递增运算符重载
先实现左移运算符的重载
再重载++运算符
前置 后置
返回什么值不知道就先写++
就返回void
cout << ++myInt << endl; 报错
需要返回自身 this 同时 解引用 加星号
MyInteger& operator++() { 返回引用 对于内置的而言 cout<<++(++a)<<endl; a连加了两次如果不返回引用 那么自己重载的a不会加两次 ,因为是返回新的对象,对新的对象进行再一次加操作//先++ m_Num++;//再返回return *this;}//后置++MyInteger operator++(int) { 涉及到了函数重载问题 int代表占位参数 区分前置和后置//先返回结果MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;// 后递增m_Num++; 自身加1//最后将记录结果返回return temp; 为什么返回值 因为 局部对象不能返回引用 这里返回的局部变量}
总结: 前置递增返回引用,后置递增返回值
赋值运算符重载
c++编译器至少给一个类添加4个函数
默认构造函数(无参,函数体为空)
默认析构函数(无参,函数体为空)
默认拷贝构造函数,对属性进行值拷贝
赋值运算符 operator=, 对属性进行值拷贝
值拷贝都会引发深浅拷贝的问题
堆区数据重复释放的问题
cout << “p1的年龄为:” << *p1.m_Age << endl;
p1.m_Age 为指针,需要解引用 *p1.m_Age 获取数据
仅仅只是用了 p2 = p1 默认的赋值运算 然后再用析构函数释放 会报错
Person& operator=(Person &p){if (m_Age != NULL) 先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝{delete m_Age;m_Age = NULL;}//编译器提供的代码是浅拷贝//m_Age = p.m_Age;//提供深拷贝 解决浅拷贝的问题m_Age = new int(*p.m_Age);//返回自身return *this; a=b=c 要有返回值 返回自身 this指针 解引用}
int *m_Age; 申明的是指针
p1.m_age
cout << “p1的年龄为:” << *p1.m_Age << endl;
cout << “p2的年龄为:” << *p2.m_Age << endl;
cout << “p3的年龄为:” << *p3.m_Age << endl;
关系运算符重载
在函数中编写
返回值bool
bool operator ==(person &p)
{
}
函数调用运算符重载
函数调用运算符 () 也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活
运算符重载很多都是引用传递
//匿名对象调用
cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
MyAdd()相当于创建了一个匿名对象 然后后面有个(100,100)
匿名对象 释放问题
地址传递和引用
引用传递 是 mySwap03(a, b); void mySwap03(int& a, int& b) {
地址传递 mySwap02(&a, &b); void mySwap02(int* a, int* b)
分文件编写
#include “…/touh/swap.h”
task,json中
“args”: [/
“F:/mycpp/cpp/test02.cpp”
1
职工管理类,作用于界面显示
相应的头文件 源文件
void WorkerManager::exitSystem()
{cout << "欢迎下次使用" << endl;system("pause");exit(0);
}
职工管理系统
7、添加职工
如果想在程序中维护这个不定长度的数组,可以将数组创建到堆区,并利用Worker **的指针维护
WorkerManager::WorkerManager() 构造函数
Worker ** newSpace = new Worker*[newSize]; 开创了一个新的work类型的数组 指针在堆区
worker类型的二次指针
if (this->m_EmpArray != NULL) 如果不是空指针 就要设置地址 不然就可以直接设置值
二级指针
int a =100;
int *p1 = &a;
int **p2 = &p1;
文件交互
在上一个添加功能中,我们只是将所有的数据添加到了内存中,一旦程序结束就无法保存了
因此文件管理类中需要一个与文件进行交互的功能,对于文件进行读写操作‘
this->m_EmpArray[i]->m_Id
this指针指向m_EmpArray[i] 得到了一个work指针 work指针再次指向m_id
ofs << this->m_EmpArray[i]->m_Id << " " << this->m_EmpArray[i]->m_Name << " " << this->m_EmpArray[i]->m_DeptId << endl;
不需要手动创建文件,它会自动创建文件并写入数据
读取文件
第一次使用,文件未创建
文件存在,但是数据被用户清空
文件存在,并且保存职工的所有数据
WorkerManager::WorkerManager()
{ifstream ifs;ifs.open(FILENAME, ios::in);//文件不存在情况if (!ifs.is_open()){cout << "文件不存在" << endl; //测试输出this->m_EmpNum = 0; //初始化人数this->m_FileIsEmpty = true; //初始化文件为空标志this->m_EmpArray = NULL; //初始化数组ifs.close(); //关闭文件return;}
}
https://gitee.com/jiangjiandong/Cpp-0-1-Resource/blob/master/%E7%AC%AC4%E9%98%B6%E6%AE%B5%E5%AE%9E%E6%88%98-%E5%9F%BA%E4%BA%8E%E5%A4%9A%E6%80%81%E7%9A%84%E4%BC%81%E4%B8%9A%E8%81%8C%E5%B7%A5%E7%B3%BB%E7%BB%9F/%E8%AE%B2%E4%B9%89/%E8%81%8C%E5%B7%A5%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F.md
https://developer.aliyun.com/article/980381#:~:text=1%E3%80%81%E9%80%90%E8%A1%8C%E8%AF%BB%E5%85%A5%E6%96%87%E4%BB%B6%20void%20readTxt%20%28string%20file%29%20%7B%20ifstream%20infile%3B,%28infile%2Cs%29%29%20%7B%20cout%3C%3Cs%3C%3Cendl%3B%20%7D%20infile.close%20%28%29%3B%20%2F%2F%E5%85%B3%E9%97%AD%E6%96%87%E4%BB%B6%E8%BE%93%E5%85%A5%E6%B5%81%20%7D
逐个字符读取
while (ifs >> id && ifs >> name && ifs >> dId)
修改职工函数实现
delete this->m_EmpArray[ret];
删除
ofstream ofs(FILENAME, ios::trunc); //打开模式 ios::trunc 如果存在删除文件并重新创建delete[] this->m_EmpArray;this->m_EmpArray = NULL; 释放原有空间,并重新指向新的