将对象的类类型保存到文件并在 C++ 中读回

Posted

技术标签:

【中文标题】将对象的类类型保存到文件并在 C++ 中读回【英文标题】:Saving an Object's class type to file and reading it back in C++ 【发布时间】:2014-10-27 09:37:55 【问题描述】:

我的程序是我有一个抽象员工类,它有 3 个继承子类,经理、研究员和工程师。

所有 3 个都有 3 个公共数据,然后是他们自己的数据要存储。

这 3 个类必须通过指向 Employee 类的指针向量存储,然后向下转换每个元素。

最后,它具有保存到文件和从文件加载的功能。

除了加载数据之外,我可以做其他所有事情。问题是在代码的开头,我如何定义向量的每个元素都是特定的继承类;例如:vec[0] 是经理,vex[1] 是工程师,等等。

这是我的所有代码。我试过的问题代码在 void MenuControl() Switch Case 5 中。

#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include<iostream>
#include <string>
#include <fstream>

using namespace std;

class Employee

    public:
        Employee();
        virtual void BasicInfo()=0;
        virtual void DisplayInfo()=0;
        virtual void SaveInfo(ofstream& outFile)=0;
        virtual void LoadInfo(ifstream& inFile)=0;
        ~Employee();
    protected:
        string f_Name, l_Name;
        int salary;
;


Employee::Employee()
Employee::~Employee()

void Employee::BasicInfo()




void Employee::DisplayInfo()



#endif
#ifndef MANAGER_H
#define MANAGER_H


#include<iostream>
#include <string>
#include <fstream>
#include "Employee.h"
using namespace std;

class Manager : public Employee

    public:
        Manager();
        Manager(string fName, string lName, int sal);
        void BasicInfo();
        void DisplayInfo();
        void SaveInfo(ofstream& outFile);
        void LoadInfo(ifstream& inFile);
        ~Manager();
    protected:
        int vacation, meets;
;
#endif


//Manager::Manager(string fName, string lName, int sal) : Employee(f_Name, l_Name, salary)
Manager::Manager()
Manager::Manager(string fName, string lName, int sal)

    f_Name = fName;
    l_Name = lName;
    salary = sal;


void Manager::BasicInfo()

    cout<<endl<<"Enter Number of Vacations: ";
    cin>>vacation;
    cout<<endl<<"Enter Number of Meetings: ";
    cin>>meets;


void Manager::DisplayInfo()

    cout<<endl<<endl<<"TYPE: Manager";
    cout<<endl<<"Name: "<<f_Name<<" "<<l_Name;
    cout<<endl<<"Salary: "<<salary<<endl;
    cout<<"Number of Vacations: "<<vacation;
    cout<<endl<<"Meetings per Week: "<<meets;
    cout<<endl<<endl<<endl;


Manager::~Manager()




void Manager::SaveInfo(ofstream& outFile)

    outFile.write((char*)&f_Name, sizeof(string));
    outFile.write((char*)&l_Name, sizeof(string));
    outFile.write((char*)&salary, sizeof(int));
    outFile.write((char*)&vacation, sizeof(int));
    outFile.write((char*)&meets, sizeof(int));


void Manager::LoadInfo(ifstream& inFile)

    inFile.read((char*)&f_Name, sizeof(string));
    inFile.read((char*)&l_Name, sizeof(string));
    inFile.read((char*)&salary, sizeof(int));
    inFile.read((char*)&vacation, sizeof(int));
    inFile.read((char*)&meets, sizeof(int));

#ifndef RESEARCHER_H
#define RESEARCHER_H


#include <iostream>
#include <string>
#include <fstream>
#include "Employee.h"
using namespace std;
class Researcher : public Employee

    public:
        Researcher();
        Researcher(string fName, string lName, int sal);
        void BasicInfo();
        void DisplayInfo();
        void SaveInfo(ofstream& outFile);
        void LoadInfo(ifstream& inFile);
        ~Researcher();
    protected:
        string TopicPhd, SchoolPhd;
;
#endif
Researcher::Researcher()
Researcher::Researcher(string fName, string lName, int sal)

    f_Name = fName;
    l_Name = lName;
    salary = sal;


void Researcher::BasicInfo()

    cout<<endl<<"Topic of PhD: ";
    cin>>TopicPhd;
    cout<<endl<<"School of PhD: ";
    cin>>SchoolPhd;


void Researcher::DisplayInfo()

    cout<<"RESEARCHER";
    cout<<endl<<"Name: "<<f_Name<<" "<<l_Name;
    cout<<endl<<"Salary: "<<salary<<endl;
    cout<<"PhD: "<<TopicPhd<<"\nSchool: "<<SchoolPhd;
    cout<<endl<<endl;


void Researcher::SaveInfo(ofstream& outFile)

    outFile.write((char*)&f_Name, sizeof(string));
    outFile.write((char*)&l_Name, sizeof(string));
    outFile.write((char*)&salary, sizeof(int));
    outFile.write((char*)&TopicPhd, sizeof(string));
    outFile.write((char*)&SchoolPhd, sizeof(string));


void Researcher::LoadInfo(ifstream& inFile)

    inFile.read((char*)&f_Name, sizeof(string));
    inFile.read((char*)&l_Name, sizeof(string));
    inFile.read((char*)&salary, sizeof(int));
    inFile.read((char*)&TopicPhd, sizeof(string));
    inFile.read((char*)&SchoolPhd, sizeof(string));

#ifndef ENGINEER_H
#define ENGINEER_H


#include <iostream>
#include <string>
#include <fstream>
#include "Employee.h"
using namespace std;

class Engineer : public Employee

    public:
        Engineer();
        Engineer(string fName, string lName, int sal);
    //  void BasicInfo(bool knowCPP, int experience, string type);
        void BasicInfo();
        void DisplayInfo();
        void SaveInfo(ofstream& outFile);
        void LoadInfo(ifstream& inFile);
        ~Engineer();
    protected:
        bool isknowingCPP;
        int exp;
        string typeOfEng;
;
#endif
Engineer::Engineer()
Engineer::Engineer(string fName, string lName, int sal)

    f_Name = fName;
    l_Name = lName;
    salary = sal;


void Engineer::BasicInfo()

    cout<<endl<<"Knows C++(0/1): ";
    cin>>isknowingCPP;
    cout<<endl<<"Years of Experience: ";
    cin>>exp;
    cout<<endl<<"Field of Engineering: ";
    cin>>typeOfEng;


void Engineer::DisplayInfo()

    cout<<"TYPE: Engineer";
    cout<<endl<<"Name: "<<f_Name<<" "<<l_Name;
    cout<<endl<<"Salary: "<<salary<<endl;
    cout<<"Knows C++: "<<isknowingCPP;
    cout<<endl<<"Experience: "<<exp;
    cout<<endl<<"Engineering: "<<typeOfEng;
    cout<<endl<<endl;


Engineer::~Engineer()




void Engineer::SaveInfo(ofstream& outFile)

    outFile.write((char*)&f_Name, sizeof(string));
    outFile.write((char*)&l_Name, sizeof(string));
    outFile.write((char*)&salary, sizeof(int));
    outFile.write((char*)&isknowingCPP, sizeof(bool));
    outFile.write((char*)&exp, sizeof(int));
    outFile.write((char*)&typeOfEng, sizeof(string));
    /*outFile<<"Engineer";
    outFile<<endl<<"FirstName: "<<f_Name;
    outFile<<endl<<"LastName: "<<l_Name;
    outFile<<endl<<"Salary: "<<salary;
    outFile<<endl<<"Knows C++: "<<isknowingCPP;
    outFile<<endl<<"Experience: "<<exp;
    outFile<<endl<<"Engineering: "<<typeOfEng;
    outFile<<endl<<endl;*/


void Engineer::LoadInfo(ifstream& inFile)

    inFile.read((char*)&f_Name, sizeof(string));
    inFile.read((char*)&l_Name, sizeof(string));
    inFile.read((char*)&salary, sizeof(int));
    inFile.read((char*)&isknowingCPP, sizeof(bool));
    inFile.read((char*)&exp, sizeof(int));
    inFile.read((char*)&typeOfEng, sizeof(string));

#include <iostream>
#include <string>
#include <vector>

#include "Engineer.h"
#include "Manager.h"
#include "Researcher.h"

using namespace std;

void MenuControl(int id);
void AddEmployee(int type);
void DeleteEmployee(int id);
int empStrength;
bool quit = false;
vector<Employee*> emps;
int main()

    /*Manager* man = new Manager("Shash", "Sharma", 30);
    emps.push_back(man);
    emps[0]->BasicInfo();*/
    int optionID;
    //delete emps[0];
    while(!quit)
    
        cout<<endl<<"1) Add Employee \n2) Delete Employee \n3)Display List \n4)Save Data \n5)Load Data \nAny other number to Quit: ";
        cin>>optionID;
        MenuControl(optionID);
    


void MenuControl(int id)

    switch(id)
    
        case 1:
            
                int empType;
                cout<<endl<<endl<<"Adding Employee..."<<endl;
                cout<<endl<<"Please choose Employee category: "<<endl<<"1)Manager\n2)Researcher\n3)Engineer\nAny other number to exit: ";
                cin>>empType;
                AddEmployee(empType);
                break;
            

        case 2:
            
                int deleteID;
                cout<<endl<<"Deleting Employee..."<<endl;
                cout<<endl<<"Enter Employee Code: ";
                cin>>deleteID;
                DeleteEmployee(deleteID);
                break;
            

        case 3:
            
                if(emps.size()>0)
                
                    for(int i=0; i<emps.size(); i++)
                    
                        emps[i]->DisplayInfo();
                    
                
                else
                    cout<<endl<<"No data available!"<<endl;

                break;
            

        case 4:
            
                if(emps.size()>0)
                
                    ofstream outfile("EmployeeData.txt", ios_base::binary);
                    for(int i=0; i<emps.size(); i++)
                    
                        emps[i]->SaveInfo(outfile);
                    
                    outfile.close();


                    ofstream outfile02("Employees.dat", ios_base::binary);
                    outfile02.write((char*)&empStrength, sizeof(int));
                    cout<<endl<<"Employee Strength: "<<empStrength;
                    outfile02.close();


                    ofstream outfile03("EmployeeTypes.txt", ios_base::binary);
                    for(int i=0; i<emps.size(); i++)
                    
                        //outfile03<<&emps[i]<<endl;
                        outfile03.write(reinterpret_cast<char*>(&emps[i]) , sizeof(Employee));
                    
                
                cout<<endl<<"Data Saved";
                cout<<endl<<endl;
                break;
            

        case 5:
            
                ifstream infile02("Employees.dat", ios_base::binary);
                infile02.read((char*)&empStrength, sizeof(int));
                cout<<endl<<"Employee Strength: "<<empStrength;
                emps.resize(empStrength);
                cout<<endl<<emps.size();

                Employee* temp;
                ifstream infile03("EmployeeTypes.txt", ios_base::binary);
    //          infile03.read(reinterpret_cast<char*>(&temp), sizeof(Employee));
                for(int i=0; i<emps.size(); i++)
                
                    cout<<endl<<"BeforeSeg";
                    infile03.read(reinterpret_cast<char*>(temp), sizeof(Employee));
                    cout<<endl<<"SegError";
                    emps[i] = temp;
                
                break;
            

        default:
            
                quit = true;
                break;
            
    


void AddEmployee(int type)

    string fName, lName;
    int sal;
    switch(type)
    
        case 1:
            
            //, holiday, meetings;
            cout<<endl<<endl<<"First Name: ";
            cin>>fName;
            cout<<endl<<"Last Name: ";
            cin>>lName;
            cout<<endl<<"Salary: ";
            cin>>sal;
            Manager* man = new Manager(fName, lName, sal);
            man->BasicInfo();
            emps.push_back(man);
            empStrength++;
            break;
            

        case 2:
            
            cout<<endl<<endl<<"First Name: ";
            cin>>fName;
            cout<<endl<<"Last Name: ";
            cin>>lName;
            cout<<endl<<"Salary: ";
            cin>>sal;
            Researcher* res = new Researcher(fName, lName, sal);
            res->BasicInfo();
            emps.push_back(res);
            empStrength++;
            break;
            

        case 3:
            
            cout<<endl<<endl<<"First Name: ";
            cin>>fName;
            cout<<endl<<"Last Name: ";
            cin>>lName;
            cout<<endl<<"Salary: ";
            cin>>sal;
            Engineer* eng = new Engineer(fName, lName, sal);
            eng->BasicInfo();
            emps.push_back(eng);
            empStrength++;
            break;
            

        default:
            cout<<endl<<endl<<"No such Employee Type. Please put correct values"<<endl;
    


void DeleteEmployee(int id)

    if(id<emps.size())
    
        emps.erase(emps.begin() + id);
        empStrength--;
    
    else
    
        cout<<endl<<"No such ID yet."<<endl;
    

我对 C++ 很陌生,所以请多多包涵:)

【问题讨论】:

【参考方案1】:

一种方法是在您的员工类中定义一个类型变量,然后在每个派生构造函数中分配该变量,然后保存/加载此信息。

快速示例代码来举例说明我的建议:

// inside Employee.h
enum eEmployeeTypes

   ET_NONE,
   ET_MANAGER,
   ET_RESEARCHER,
   ET_ENGINEER


class Employee

  ...
  protected:
  eEmployeeTypes m_Type;


//employee cpp
Employee::Employee()

  ...
  m_Type = ET_NONE


// Sample modified constructor for Manager
// manager.cpp
Manager::ManageR()

  ...
  m_Type = ET_MANAGER;

现在是棘手的部分,因为您在加载时需要信息:

您应该首先将类型信息保存在文件中。

然后您应该为 Employee 创建一个 Factory 函数,它使用适当的构造函数并读取如下内容:

static Employee* CreateEmployeeFromFile(ifstream& file)

    eEmployeeTypes type;
    file.read((eEmployeeTypes*)&type, sizeof(eEmployeeTypes));
    Employee* rez=null;
    if (type == ET_MANAGER)
    
       rez = new Manager();
       rez.LoadInfo(file);
    
    ...
    return rez;

【讨论】:

好的,我会测试你的方法。但是,如果我只是在数据中放置一个与每个 Employee 类型相关的 int ,而不是 Enum ,那也可以吗?例如:我将 Manager 设置为 1,Researcher 设置为 2 等等,然后在加载时从文件中读取,运行 switch 或 if 循环,就像你正在做的那样,并将每个元素实例化为相同?总之非常感谢。我会测试它并在一段时间内批准答案:) 枚举和整数实际上在 C++ 中是一回事,它只是帮助您获得连续递增的常量值。编译器可能会选择将枚举转换为 byte / short ,这就是为什么在使用枚举时使用 sizeof 枚举而不是直接假设它是一个 int 更安全。 哦,好的。因此,在将其保存为二进制文件时,我将其大小指定为 sizeof(eEmployeeTypes)? 如果你使用枚举,是的,这就是你想要的:)。您可以做的一个小技巧是强制枚举为 int ,因此如果您使用不同的编译器,以后就不会遇到不匹配的情况。这是技巧的链接(第二个答案是您要搜索的答案):***.com/questions/4879286/… 抱歉回复晚了。我尝试以与您完全相同的方式进行操作,但它给出了一些错误,所以我只是简单地纠正了错误,我很高兴!非常感谢您的帮助! :)

以上是关于将对象的类类型保存到文件并在 C++ 中读回的主要内容,如果未能解决你的问题,请参考以下文章

如何在 XCTestCase 中测试 NSPersistentDocument?

如何使用 protobuf-net 读回附加的对象?

从向量中保存的类对象输出类函数

笔记:I/O流-对象序列化

Android 上的 ProGuard 和 Gson (ClassCastException)

如何将文件存储到包含 C++ 中的类对象的向量中?