C ++ проблемы с RTTI или двоичным файлом IO - PullRequest
0 голосов
/ 17 ноября 2010

Я думаю, у меня проблемы с двоичным файлом io. Если я запускаю свою программу, создаю несколько объектов сотрудников и затем отображаю их, все работает нормально. Если я сохраняю данные объекта и перезагружаю программу, я получаю исключение RTTI. Мне кажется, что мои функции LoadEmployeeData () и Savelist (vector & e) работают очень хорошо. Исключение возникает в моей функции DisplayEmployeeData (), когда я пытаюсь использовать typeid.

Просто повторюсь, я получаю ошибку RTTI при использовании typeid на объекте, загруженном с диска.

//****************header file***********
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <typeinfo>
#include <ctime>
#include <cstdlib>
using namespace std;
class Employee
{
private:
    int employeeID;
    char name[80];
    int SSN;
public:
    Employee();
    Employee(int, char*,int);
    virtual ~Employee();
    virtual void DisplayBaseData();
    //getters
    int GetID();
    char* getName();
    int GetSSN();
    //setters
    void SetID(int);
    void SetName(char*);
    void SetSSN(int);
};//end Employee class

class Salary : public Employee
{
private:
    double salary;
public:

    Salary();
    Salary(int, char*, int, double); //id, name, ssn, salary
    ~Salary();
    void DisplayEmployeeData();
    //getters
    double GetSalary();
    //setters
    void SetSalary(double);
};//end class Exempt

class Hourly : public Employee
{
private:
    double rate;
    double hoursWorked;
public:
    Hourly();
    Hourly(int, char*, int, double, double); //id, name, ssn, rate
    ~Hourly();
    void DisplayEmployeeData();
    //getters
    double GetRate();
    double GetHoursWorked();
    //setters
    void SetRate(double);
    void SetHoursWorked(double);
};//end Hourly Class

    const int HOURLYTYPE = 0;
    const int SALARYTYPE = 1;

// ******* корпус *******

#include "lab05.h";


Employee::Employee(){};
Employee::Employee(int ID, char* nme, int ssn) : employeeID(ID), SSN(ssn)
{
    strcpy(name, nme);
}
int Employee::GetID()
{
    return employeeID;
}
char* Employee::getName()
{
    return name;
}
int Employee::GetSSN()
{
    return SSN;
}
void Employee::SetID(int i)
{
    employeeID = i;
}
void Employee::SetName(char* n)
{
    strcpy(name, n);
}
void Employee::SetSSN(int i)
{
    SSN = i;
}
void Employee::DisplayBaseData()
{
    cout << "ID: \t" << employeeID << endl;
    cout << "Name: \t " << name << endl;
    cout << "SSN: \t" << SSN << endl;
}
Employee::~Employee(){}


Salary::Salary(){}
Salary::Salary(int id, char* nme, int ssn, double slry) : Employee(id, nme, ssn), salary(slry){}
void Salary::DisplayEmployeeData()
{
    DisplayBaseData();
    cout << "Salary: \t " << salary << endl;
}
double Salary::GetSalary()
{
    return salary;
}

void Salary::SetSalary(double d)
{
    salary = d;
}
Salary::~Salary(){}


Hourly::Hourly(){}
Hourly::Hourly(int id, char* nme, int ssn, double rte, double worked) : Employee(id, nme, ssn), rate(rte), hoursWorked(worked){}
void Hourly::DisplayEmployeeData()
{
    DisplayBaseData();
    cout << "Rate: \t" << rate << endl;
    cout << "Worked: \t " << hoursWorked << endl;
}
double Hourly::GetRate()
{
    return rate;
}
double Hourly::GetHoursWorked()
{
    return hoursWorked;
}
void Hourly::SetRate(double d)
{
    rate = d;
}
void Hourly::SetHoursWorked(double d)
{
    hoursWorked = d;
}
Hourly::~Hourly(){}




vector<Employee*> LoadEmployeeData()
{

    vector<Employee*> employeeList;
    string fileName = "";
    cout << "\nEnter filename for employee data: ";
    cin >> fileName;
    fstream file;


    file.open(fileName, ios::in, ios::binary);
    char buffer[4096] = {0};
    int numEntries;
    file.read((char*)&numEntries, sizeof(int));
    cout << numEntries << " number of entries found." << endl;
    if (numEntries != 0)
    {
        int identifier;
        for (int i = 0; i < numEntries; i++)
        {
            file.read((char*)&identifier, sizeof(int));
            if (identifier == SALARYTYPE)
            {
                Employee* temp = new Salary();
                file.read((char*)temp, sizeof(Salary));
                employeeList.push_back(temp);
            }
            else if (identifier == HOURLYTYPE)
            {
                Employee* temp = new Hourly();
                file.read((char*)temp, sizeof(Hourly));
                employeeList.push_back(temp);
            }
        }
    }
    else cout << "No Entries found." << endl;

    file.close();
    return employeeList;
}//end LoadEmployeeData function

void ListEmployees(vector<Employee*> &e)
{
    if (e.size() != 0)
    {
        for (int i = 0; i < e.size(); i++)
        {
            if (typeid(*(e[i])) == typeid(Hourly))
            {
                cout << "\n(" << i << ")" << endl;
                dynamic_cast<Hourly*>(e[i])->DisplayEmployeeData();
            }

            else if (typeid(*(e[i])) == typeid(Salary))
            {
                cout << "\n(" << i << ")" << endl;
                dynamic_cast<Salary*>(e[i])->DisplayEmployeeData();
            }
        }
    }
    else cout << "No items in list" << endl;    
}// end ListEmployees function

void ModifyEmployee(vector<Employee*> &e)
{
    cout << "Enter employee selection." << endl;
}

void CreateEmployee(vector<Employee*> &e)
{
    bool continueLoop = true;
    srand(time(0)); //seed random number generator

    cout << "\n Enter new employee information." << endl;
    cout << "Name: ";
    char newName[80] = {0};
    cin >> newName;
    cout << "\n SSN: ";
    int newSSN;
    cin >> newSSN;
    char newType = '-1';
    do
    {
        cout << "\n Is new employee paid a (s)alary or (h)ourly rate? ";
        cin >> newType;
        if (newType == 's' || newType == 'h') continueLoop = false;
        else cout << "incorrect input" << endl;
    }while (continueLoop == true);
    if (newType == 's')
    {
        cout << "Enter salary amount: ";
        double amount;
        cin >> amount;
        e.push_back(new Salary(rand() % 1000 + 1, newName, newSSN, amount));
    }
    else if (newType == 'h')
    {
        cout << "Enter hourly amount: ";
        double amount;
        cin >> amount;
        cout << "Enter hours worked: ";
        double hoursWorked;
        cin >> hoursWorked;
        e.push_back(new Hourly(rand() % 1000 + 1, newName, newSSN, amount, hoursWorked));
    }
}

void Savelist(vector<Employee*> &e)
{
    if (e.size() == 0)
        cout << "No employees in list.  Nothing done." << endl;
    else 
    {
        cout << "Enter save filename: ";
        char fileName[80] = {'\0'};
        cin >> fileName;
        fstream* file = new fstream();
        file->open(fileName, ios::out, ios::binary);
        char buffer[80] = {'\0'};
        int numEntries = e.size();
        file->write((char*)&numEntries, sizeof(int)); //writes number of entries

        for (int i = 0; i < e.size(); i++)
        {
            if (typeid(*e[i]) == typeid(Salary))
            {   
                int classType = SALARYTYPE;
                file->write((char*)&classType, sizeof(int));
                file->write((char*)dynamic_cast<Salary*>(e[i]), sizeof(Salary));
            }
            else if (typeid(*e[i]) == typeid(Hourly))
            {
                int classType = HOURLYTYPE;
                file->write((char*)&classType, sizeof(int));
                file->write((char*)dynamic_cast<Hourly*>(e[i]), sizeof(Salary));
            }
        }
        file->close();
    }

}

void DeleteEmployee(vector<Employee*> &e)
{
    cout << "Input index number of employee to delete: ";
    int idx = 0;
    cin >> idx;
    if (idx > e.size() -1)
        cout << "invalid index number\n" << endl;
    else
    {
        delete e[idx];
        e.erase(e.begin() + idx); //removes from list
    }
}


int main()
{


    const int ZERO = 0;
    const int ONE = 1;
    const int TWO = 2;
    const int THREE = 3;
    const int FOUR = 4;
    const int FIVE = 5;
    const int SIX = 6;

    int exitMainLoop = false;  //for flow control
    int mainMenuChoice = -1;
    vector<Employee*> employeeList;
    do
    {
        cout << "Select from the following options." << endl;
        cout << "(1) Load employee data file." << endl;
        cout << "(2) View Employees." << endl;
        cout << "(3) Modify Employee data. " << endl;
        cout << "(4) Create new employee." << endl;
        cout << "(5) Save list to file." << endl;
        cout << "(6) Delete employee data. " << endl;
        cout << "(0) Exit program." << endl;

        //add more options
        cout << "Enter selection: ";
        cin >> mainMenuChoice;
        if (cin.fail())
        {
            cout << "\nInvalid selection.  Try again" << endl;
            cin.clear();
            string garbage = "";
            cin >> garbage;
        }
        else if (mainMenuChoice == ONE)
            employeeList = LoadEmployeeData();
        else if (mainMenuChoice == TWO)         
            ListEmployees(employeeList);
        else if (mainMenuChoice == THREE)
            ModifyEmployee(employeeList);
        else if (mainMenuChoice == FOUR)
            CreateEmployee(employeeList);
        else if (mainMenuChoice == FIVE)
            Savelist(employeeList);
        else if (mainMenuChoice == SIX)
            DeleteEmployee(employeeList);
        else if (mainMenuChoice == ZERO)
            exitMainLoop = true;

    }while(exitMainLoop == false);
    system("PAUSE");
}

Ответы [ 2 ]

0 голосов
/ 17 ноября 2010

файл-> запись ((символ *) dynamic_cast(e [i]), sizeof (Зарплата));

выглядит подозрительно.Вы имели в виду sizeof (ежечасно)?

0 голосов
/ 17 ноября 2010

Вы не можете читать / записывать необработанные объекты C ++ с / на диск, если они имеют виртуальные методы (или используют RTTI, для которого требуются виртуальные методы), потому что нет гарантии, что адрес vtable из первого выполнения будет записан на диск,и нет никакой гарантии, что vtable будет в том же месте при следующем запуске программы - следовательно, адрес, который был записан на диск, будет указывать где-то неверно, когда он будет прочитан обратно.

...