使用 Metadata/Inheritance 分解多个 类 中的代码
Using Metadata/Inheritance to factor out code across multiple classes
我有两个 class 表示两个非常简单的数据库,每个都有一个 "Save" 函数,可以将 class 中的内容写入文件。由于 "Save" 函数中的代码非常相似,我想知道是否可以分解出来。
我的一位同事说这可能通过继承 and/or 元数据实现,所以我尝试通过 Google 自己研究它。但是,我找不到任何有用的东西,我仍然不确定我想做的事情是否可行。
如果可以分解,那么我想我需要让另一个 class 或函数知道每个 class 的类型并以某种方式遍历它们(元数据?)。它会检查每个数据的类型,并根据类型确定它是否正确输出到文本文件。
(我知道姓名、年龄等数据应该是私有的,但为了简单起见,我将所有内容设为 public)
class A
{
public:
A() : name(""), age(0) {};
void Save(void)
{
std::string filename = "A.txt";
std::string data;
data += name + "\n";
data += std::to_string(age) + "\n";
std::ofstream outfile(filename);
outfile.write(data.c_str(), data.size());
outfile.close();
}
std::string name;
int age;
};
class B
{
public:
B() : ID(0), points(0) {};
void Save(void)
{
std::string filename = "B.txt";
std::string data;
data += std::to_string(ID) + "\n";
data += std::to_string(points) + "\n";
std::ofstream outfile(filename);
outfile.write(data.c_str(), data.size());
outfile.close();
}
int ID;
int points;
};
int main(void)
{
A a;
B b;
a.name = "Bob"; a.age = 20;
b.ID = 4; b.points = 95;
a.Save();
b.Save();
return 0;
}
一个可能的解决方案是使用元编程(不确定元数据是什么意思),即重复使用公共部分的模板
template<typename T1, typename T2>
void TSave(const std::string fname, const T1& p1, const T2& p2) {
std::string filename = fname;
std::stringstream data;
data << p1 << "\n";
data << p2 << "\n";
std::ofstream outfile(filename);
outfile.write(data.str().c_str(), data.str().size());
outfile.close();
}
class A {
...
void Save(void) {
TSave("A.txt", name, age);
}
std::string name;
int age;
};
class B {
...
void Save(void) {
TSave("B.txt", ID, points);
}
int ID;
int points;
};
您正在寻找的是 serialization:将对象保存到文件(并且有一天,恢复对象)。
当然,您可以编写自己的序列化框架,而 Marco 的回答是朝着这个方向迈出的一个有趣的开端。但或者,您可以考虑现有的库,例如 boost::serialization
:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class A {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & name;
ar & age;
}
...
};
class B {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & ID;
ar & points;
}
...
};
main() {
A a;
B b;
...
{
std::ofstream ofs("myfile");
boost::archive::text_oarchive arch(ofs);
arch << a << b;
}
}
如您所见,仍然需要说明要写入文件的内容。然而,代码被简化了:您不必担心文件管理和数据转换。它也适用于标准容器。
您不会找到自动确定 class 要保存的内容的 C++ 技巧。两个原因:
- C++ 允许元编程,但它不是自反的:没有标准过程可以在执行时找出哪些成员组成 class。
- 在一个对象中,一些数据可能是暂时的,即它仅在执行时表示某些内容并且取决于上下文。例如指针:您可以将指针的值保存到一个文件,但是当您稍后重新加载它时它将毫无意义(指针仅在您释放对象之前有效)。正确的方法是保存指向的对象(但在哪里,何时,如何?)。
我有两个 class 表示两个非常简单的数据库,每个都有一个 "Save" 函数,可以将 class 中的内容写入文件。由于 "Save" 函数中的代码非常相似,我想知道是否可以分解出来。
我的一位同事说这可能通过继承 and/or 元数据实现,所以我尝试通过 Google 自己研究它。但是,我找不到任何有用的东西,我仍然不确定我想做的事情是否可行。
如果可以分解,那么我想我需要让另一个 class 或函数知道每个 class 的类型并以某种方式遍历它们(元数据?)。它会检查每个数据的类型,并根据类型确定它是否正确输出到文本文件。
(我知道姓名、年龄等数据应该是私有的,但为了简单起见,我将所有内容设为 public)
class A
{
public:
A() : name(""), age(0) {};
void Save(void)
{
std::string filename = "A.txt";
std::string data;
data += name + "\n";
data += std::to_string(age) + "\n";
std::ofstream outfile(filename);
outfile.write(data.c_str(), data.size());
outfile.close();
}
std::string name;
int age;
};
class B
{
public:
B() : ID(0), points(0) {};
void Save(void)
{
std::string filename = "B.txt";
std::string data;
data += std::to_string(ID) + "\n";
data += std::to_string(points) + "\n";
std::ofstream outfile(filename);
outfile.write(data.c_str(), data.size());
outfile.close();
}
int ID;
int points;
};
int main(void)
{
A a;
B b;
a.name = "Bob"; a.age = 20;
b.ID = 4; b.points = 95;
a.Save();
b.Save();
return 0;
}
一个可能的解决方案是使用元编程(不确定元数据是什么意思),即重复使用公共部分的模板
template<typename T1, typename T2>
void TSave(const std::string fname, const T1& p1, const T2& p2) {
std::string filename = fname;
std::stringstream data;
data << p1 << "\n";
data << p2 << "\n";
std::ofstream outfile(filename);
outfile.write(data.str().c_str(), data.str().size());
outfile.close();
}
class A {
...
void Save(void) {
TSave("A.txt", name, age);
}
std::string name;
int age;
};
class B {
...
void Save(void) {
TSave("B.txt", ID, points);
}
int ID;
int points;
};
您正在寻找的是 serialization:将对象保存到文件(并且有一天,恢复对象)。
当然,您可以编写自己的序列化框架,而 Marco 的回答是朝着这个方向迈出的一个有趣的开端。但或者,您可以考虑现有的库,例如 boost::serialization
:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class A {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & name;
ar & age;
}
...
};
class B {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & ID;
ar & points;
}
...
};
main() {
A a;
B b;
...
{
std::ofstream ofs("myfile");
boost::archive::text_oarchive arch(ofs);
arch << a << b;
}
}
如您所见,仍然需要说明要写入文件的内容。然而,代码被简化了:您不必担心文件管理和数据转换。它也适用于标准容器。
您不会找到自动确定 class 要保存的内容的 C++ 技巧。两个原因:
- C++ 允许元编程,但它不是自反的:没有标准过程可以在执行时找出哪些成员组成 class。
- 在一个对象中,一些数据可能是暂时的,即它仅在执行时表示某些内容并且取决于上下文。例如指针:您可以将指针的值保存到一个文件,但是当您稍后重新加载它时它将毫无意义(指针仅在您释放对象之前有效)。正确的方法是保存指向的对象(但在哪里,何时,如何?)。