【发布时间】:2021-09-12 13:44:32
【问题描述】:
我有一个虚拟父类,用于收集报告及其关联的报告结构。报告最后应该呈现为 JSON 字符串,所以我使用 https://github.com/nlohmann/json 来帮助我。
我创建不同的不同子类来生成相应子报表结构的此类报表,挑战在于每个子报表可能具有略微不同的字段,但从父级继承一些。我有将结构转换为 JSON 表示所需的宏,按报告类型定义。这是到目前为止的代码:
/**
* Compile with nlohmann json.hpp
*/
#include <iostream>
#include <vector>
#include <memory>
#include "json.hpp"
using json = nlohmann::json;
struct Report {
// make abstract
virtual ~Report() {}
std::string type = "main_report";
int foo = 0;
};
struct ChildAReport : public Report {
std::string type = "child_a_report";
int bar = 1;
};
struct ChildBReport : public Report {
std::string type = "child_b_report";
int baz = 2;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ChildAReport, type, foo, bar)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ChildBReport, type, foo, baz)
class Parent {
protected:
std::vector<std::shared_ptr<Report>> reports;
virtual void run() = 0;
virtual std::string get_report() = 0;
};
class ChildA : public Parent {
public:
virtual void run() override
{
ChildAReport r;
r.foo = 1;
r.bar = 2;
reports.push_back(std::make_shared<ChildAReport>(r));
}
std::string get_report() override {
std::shared_ptr<Report> r = reports.back();
std::shared_ptr<ChildAReport> cr = std::dynamic_pointer_cast<ChildAReport>(r);
json r_json = *cr;
return r_json.dump();
}
};
class ChildB : public Parent {
public:
virtual void run() override
{
ChildBReport r;
r.foo = 1;
r.baz = 3;
reports.push_back(std::make_shared<ChildBReport>(r));
}
std::string get_report() override {
std::shared_ptr<Report> r = reports.back();
std::shared_ptr<ChildBReport> cr = std::dynamic_pointer_cast<ChildBReport>(r);
json r_json = *cr;
return r_json.dump();
}
};
int main(int argc, char *argv[])
{
ChildA ca = ChildA();
ca.run();
std::cout << ca.get_report() << std::endl;
ChildB cb = ChildB();
cb.run();
std::cout << cb.get_report() << std::endl;
}
代码使用json.hpp 编译,没有其他依赖项。
我期待这个输出:
{"bar":2,"foo":1,"type":"child_a_report"}
{"baz":3,"foo":1,"type":"child_b_report"}
现在,为了实际生成 JSON,我使用了get_report() 方法。我了解到我必须将downcast the pointer 转换为Report 结构到实际的ChildA 或ChildB 结构,否则它将无法正确转换为JSON。这很乏味;如您所见,代码在每个可能的子类中几乎逐字重复。 run() 函数不是问题所在——这就是各种魔法发生的地方,每个类都不同。
有没有一种方法可以将它拉到父类,而不必在转换为 JSON 之前明确指定要进行的转换类型?理想情况下,这可以根据get_report() 正在运行的实际类型来推断...
【问题讨论】:
-
我认为您正在查看visitor pattern。这将避免指针的转换。
-
啊,我承认我在寻求一个我心目中的特定解决方案,而不是考虑完全不同的架构选择。不过,访问者模式似乎有点复杂。我仍然需要为每个执行导出的子类创建一个新方法,不是吗? (类似于
visitCircle与visitRectangle等)
标签: c++ c++11 shared-ptr