此代码有效,但这样做的正确方法是什么?
我的意思是,如何消除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);
}
}
答案 0 :(得分:0)
以下是一个(众多)选项:
首先,我们将enum class animal_type
更改为普通的枚举,因为我们希望将其用作整数。如果不允许,请将其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);}
};
Documentation on std::function
Documentation on Lambda expressions
接下来定义在发生坏事时要抛出的异常。可以像
一样简单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();
}
}