You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++对象与多态文件流程序:读取文件后显示崩溃问题求助

C++多态对象文件读写崩溃问题排查与解决

问题描述

基于Robert Lafore所著《C++面向对象编程》第12章(对象与多态的文件流)编写的程序,添加员工、显示员工、写入文件功能均正常,但关闭程序重新运行后,读取文件数据再执行显示操作时崩溃,报错为Process finished with exit code 139 (interrupted by signal 11: SIGSEGV),开发环境为Mac系统下的Clion。

崩溃原因

  • 虚函数表指针无效:带有虚函数的类对象内存中会存储虚函数表指针(vptr),直接将对象二进制写入文件时,会把当前进程的虚函数表指针一并写入。重启程序后读取数据,该指针指向旧进程的无效内存地址,调用gettype()、putdata()等虚函数时触发段错误。
  • 对象内存布局不兼容:不同编译环境或同一环境的不同编译配置下,类对象的内存布局可能存在差异,直接二进制读写对象会导致数据解析错误,引发内存访问异常。

解决办法

需避免直接读写整个对象,改为序列化/反序列化对象的成员变量,具体修改步骤如下:

1. 修改write()函数:分类型写入成员变量

不再直接写入整个对象,而是逐个写入基类和派生类的成员数据:

void employee::write()
{
    etype type;
    ofstream file("Data.DAT", ios::binary);
    for(int i=0;i<n;i++)
    {
        type = e[i]->gettype();
        file.write(reinterpret_cast<char*>(&type), sizeof(etype));
        switch(type)
        {
            case managerr:
            {
                manager* m = static_cast<manager*>(e[i]);
                // 写入基类成员
                file.write(reinterpret_cast<char*>(m->name), 40);
                file.write(reinterpret_cast<char*>(&m->number), sizeof(int));
                // 写入派生类成员
                file.write(reinterpret_cast<char*>(m->title), 40);
                file.write(reinterpret_cast<char*>(&m->dues), sizeof(double));
                break;
            }
            case scientistt:
            {
                scientist* s = static_cast<scientist*>(e[i]);
                file.write(reinterpret_cast<char*>(s->name), 40);
                file.write(reinterpret_cast<char*>(&s->number), sizeof(int));
                file.write(reinterpret_cast<char*>(&s->pubs), sizeof(int));
                break;
            }
            case laborerr:
            {
                laborer* l = static_cast<laborer*>(e[i]);
                file.write(reinterpret_cast<char*>(l->name), 40);
                file.write(reinterpret_cast<char*>(&l->number), sizeof(int));
                break;
            }
            default: cout<<"Can't write type"<<endl;
        }
    }
    file.close();
}

2. 修改read()函数:分类型读取并赋值成员变量

创建新对象后,逐个读取文件中的成员数据并赋值:

void employee::read()
{
    etype type;
    ifstream file("Data.DAT", ios::binary);
    while(true)
    {
        file.read(reinterpret_cast<char*>(&type), sizeof(etype));
        if(file.eof())
            break;
        switch(type)
        {
            case managerr:
            {
                manager* m = new manager;
                e[n] = m;
                // 读取基类成员
                file.read(reinterpret_cast<char*>(m->name), 40);
                file.read(reinterpret_cast<char*>(&m->number), sizeof(int));
                // 读取派生类成员
                file.read(reinterpret_cast<char*>(m->title), 40);
                file.read(reinterpret_cast<char*>(&m->dues), sizeof(double));
                break;
            }
            case scientistt:
            {
                scientist* s = new scientist;
                e[n] = s;
                file.read(reinterpret_cast<char*>(s->name), 40);
                file.read(reinterpret_cast<char*>(&s->number), sizeof(int));
                file.read(reinterpret_cast<char*>(&s->pubs), sizeof(int));
                break;
            }
            case laborerr:
            {
                laborer* l = new laborer;
                e[n] = l;
                file.read(reinterpret_cast<char*>(l->name), 40);
                file.read(reinterpret_cast<char*>(&l->number), sizeof(int));
                break;
            }
            default: cout<<"Can't read type"<<endl;
        }
        n++;
    }
}

3. 调整基类成员访问权限

为了让派生类能直接访问基类的name和number成员,将employee类的成员访问权限从private改为protected:

class employee
{
protected:
    char name[40];
    int number;
public:
    // 其余成员函数不变
};

内容的提问来源于stack exchange,提问作者Mohamed Helmy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:40:55