基于多态的职工管理系统——2/3部分(文件交互)

1、写文件

①在workerManager.h中添加宏常量,并且包含头文件 fstream

②成员函数声明

在workerManager.h中类里添加成员函数 void save()

③保存文件功能实现

ios::out 模式会:

  1. 如果文件存在,则打开文件并清空其内容(即文件内容会被覆盖)。

  2. 如果文件不存在,则创建一个新文件。

workerManager.cpp实现:

职工管理系统.cpp:调用成员函数,测试成功:

后续修改、删除等操作后,都需要再次调用save()函数。

2、读文件

每次开始运行程序,将文件中数据读取到程序中,在构造函数中实现。分情况:

为了避免在程序多个地方重复检查文件状态,可以通过标志清晰地表达:在workerManager.h中添加新的成员属性:bool m_FileIsEmpty,标志文件是否为空。

①文件不存在

is_open() 的注意事项:

       a.文件路径:确保文件路径正确。相对路径是相对于程序运行时的当前工作目录,绝对路径Windows 中使用 \\,Linux 中使用 /。

        b.文件权限确保程序有权限访问文件。例如,在 Linux 中,如果文件权限为 rw-r--r--,则会返回 false

       c.文件流状态:is_open() 只检查文件是否成功打开,不检查文件是否为空或是否有有效数据。

删除文件后,测试初始化数据功能,成功。

②文件存在且数据为空

在workerManager.cpp中的构造函数追加代码:

       a.为什么要先读取一个字符?

       当你尝试使⽤"ifs >> ch"或 "ifs.get(ch)"读取⼀个字符时, 由于⽂件为空, 读取操作会失败,⽂件流会⽴即触发"EOF 状态", ch没有被成功读取,值保持不变, 可能是未定义的或初始值。

       而直接调⽤“ifs.eof()”会返回 false, 因为⽂件指针还没有尝试读取任何内容, 程序并不知道是否已经到达⽂件末尾。

       ifs >> ch 会跳过空白字符(如空格、换行符等),可能会造成误判。

        b.文件指针

        当你打开一个文件时,文件指针默认位于文件的开头(即位置 0)。   

  ifs >> ch 读取成功,文件指针会移动到下一个字符的位置。读取失败,文件指针不会移动。

       可以使用 tellg() 来获取当前文件指针的位置:

测试:

       c.一些新方法

       1)peek() 是 ifstream 的一个成员函数,用于查看文件中的下一个字符,但不会移动文件指针。如果文件为空,peek() 会返回 EOF。同样,它会跳过空白字符(如空格、换行符等),可能导致误判。

       2)seekg 和 tellg 是 ifstream 的成员函数,通过将文件指针移动到文件末尾并检查文件大小,可以准确判断文件是否为空。文件大小计算包括换行符和文件结束符。

将文件创建后清空文件内容,测试初始化功能,成功。

③文件存在且保存职工数据

        在C++中,动态数组的内存分配是一次性完成的,需要在创建数组时指定其大小。如果尝试在不知道大小的情况下逐个添加对象,可能会导致内存分配失败或内存浪费。

      a.获取记录的职工人数,开辟空间

在workerManager.h中添加成员函数 int get_EmpNum(); 

workerManager.cpp实现:

WorkerManager.cpp添加代码,手动添加一些职工数据,测试获取职工数量函数,成功。

        b. 初始化数组

在WorkerManager.h中添加成员函数 void init_Emp();

workerManager.cpp实现:

注意:在循环的末尾,不要添加:delete worker :

  • m_EmpArray[index] 中的指针变成一个悬空指针虽仍然指向原来的内存地址,但指向的内存被释放,访问它会导致未定义行为(通常是程序崩溃或数据损坏)。

  • 对象无法访问

WorkerManager.cpp继续添加代码,测试成功。

3、清空文件

在workerManager.h中添加成员函数 void Clean_File();

     

workerManager.cpp实现:

职工管理系统.cpp:case7分支调用成员函数,测试成功。

        a.ios::trunc

  • 如果文件已经存在,会清空文件内容(即将文件大小截断为 0)。

  • 如果文件不存在,会自动创建一个空文件。

        b.delete[] m_EmpArray

  • 如果数组元素是普通对象(非指针)delete[] m_EmpArray 会:调用每个数组元素的析构函数,并释放整个数组的内存。不需要手动释放数组中的每个对象。

  • 如果数组元素是指针,delete[] m_EmpArray 只会:释放数组本身的内存(即指针数组的内存),不会释放指针指向的对象需要手动释放数组中的每个对象,否则会导致内存泄漏。

        c.析构函数怎么办呢?

     手动调用Clean_File():显式的清理,析构函数:在对象销毁时自动调用。如过 Clean_File() 被调用过,m_EmpArray 已经被释放并置空,析构函数再次释放会导致重复释放。如果 Clean_File() 没有被调用,析构函数必须释放 m_EmpArray,否则会导致内存泄漏。

        为了避免重复释放,同时确保资源在任何情况下都能被正确释放,可以采用以下方法:

方法 1:使用标志位

        在类中添加一个标志位(如 bool m_IsCleaned; // 标志位),用于记录 Clean_File() 是否被调用过。在析构函数中根据标志位决定是否释放资源。

方法 2:使用智能指针

        使用 std::unique_ptr 或 std::shared_ptr 管理动态内存,避免手动释放内存的麻烦。

补充:nullptr 和 NULL 的区别:

碎碎念:

回家真幸福,每一位妇女都是最棒的!❤

背挺直一点,向前站一点,走好自己选择的路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值