将继承的类存储到文件的更好方法

Better way to store inherited class to the file

本文关键字:文件 更好 方法 存储 继承      更新时间:2023-10-16

这段代码有效,但正确的方法是什么?

我的意思是,我怎样才能消除read_in函数中的switch语句,或者处理动物类或其子类中的所有读取,这样我的read_in函数就可以像我的write_out函数一样简单?

我有一个装满猫和普通动物的vector<animal*> *animals,我需要在文件中写入/读取/读取。

我省略了一些代码,所以帖子不会太大......

enum class animal_type
{
    GENERIC_ANIMAL,
    CAT
};

假设我有一只类动物

class animal
{
    animal_type m_type;
    string m_name;
    virtual void write_binary(ofstream &out)
    {
        out.write((char*)(&m_type), sizeof(m_type)); //first 'animal_type'
        out.write((char*)(&m_type), sizeof(m_type)); //second 'animal_type'
        out.write(m_name.c_str(), m_name.size()+1);
    {
    virtual void read_binary(std::ifstream &in)
    {
        in.read((char*)(&m_type), sizeof(m_type)); //read the second animal type here
        m_name = read_null_string(in);//this function returns next string from input
    }
};

以及源自动物的类

class cat : public animal
{
    bool m_is_cute;
    void write_binary(std::ofstream &out)
    {
        animal::write_binary(out);
        out.write((char*)(&m_is_cute), sizeof(m_is_cute));
    }
    void read_binary(std::ifstream &in)
    {
        animal::read_binary(in);
        in.read((char*)(&m_is_cute), sizeof(m_is_cute));
    }
 };

我将它们写入这样的文件

void write_out(std::ofstream &out, std::vector<animal*> *animals)
{
    int size = animals->size();
    out.write((char*)(&size), sizeof(size));
    for(animal* a : *animals)
    {
        a->write_binary(out);
    }
}

并像这样从文件中读取它们

void read_in(std::ifstream &in, std::vector<animal*> *animals)
{
    animals->clear();
    int size;
    in.read((char*)(&size), sizeof(size));
    for(int i = 0; i< size; ++i)
    {
        animal_type type;
        //read the first 'animal_type' here
        in.read((char*)(&type), sizeof(type));
        animal *a;
        switch(type)
        {
            case(animal_type::GENERIC_ANIMAL):
            a = new animal(in);//this constructor just calls the read_binary method
            break;
            case(animal_type::CAT):
            a = new cat(in);//this constructor just calls the read_binary method
            break;
        }
        animals->push_back(a);
    }
}

这是(许多)选项中的一个:

首先,我们将enum class animal_type更改为一个普通的旧枚举becaysuse,我们希望将其用作整数。如果不允许这样做,请将其保留为enum class animal_type,并在以后使用static_cast<size_t>进行转换。

enum animal_type
{
    GENERIC_ANIMAL = 0, // must be 0. First index in array
    CAT,
    LAST, // must be last. Put no animals after it
    FIRST  = GENERIC_ANIMAL // makes it easy to loop FIRST to LAST
};

然后定义你所有的动物。

接下来,构建一个调用相应动物构造函数的函数数组。此数组必须与上面的枚举完全匹配。如果这是一个问题,请考虑改用std::map

std::function<animal *(std::ifstream &)> animalFactory[] =
{
    [](std::ifstream & in) {return new animal(in);},
    [](std::ifstream & in) {return new cat(in);}
};

关于 std::function 的文档

有关 Lambda 表达式的文档

接下来定义在发生坏事时要引发的异常。可以像

class Bogus_File_Exception: public std::exception
{
    const char* what() const
    {
        return "File read failed.";
    }
};

最后read_in变成了

void read_in(std::ifstream &in, std::vector<animal*> & animals) // note the reference
{
    animals.clear();
    int size;
    if (in.read((char*)(&size), sizeof(size))) // testing for successful read
    {
        for(int i = 0; i< size; ++i)
        {
            animal_type type;
            if (in.read((char*)(&type), sizeof(type))) // testing again
            {
                if (type < animal_type::LAST)
                {
                    animals.push_back(animalFactory[type](in));
                }
                else
                {
                    throw Unknown_Animal_Exception();
                }
            }
            else
            {
                throw Bogus_File_Exception();
            }
        }
    }
    else
    {
        throw Bogus_File_Exception();
    }
}