我有一个虚拟父类,用于收集带有关联报告结构的报告。报告应该最终呈现为 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()
方法。我知道我不得不垂头丧气指针到Report
结构到实际ChildA
或ChildB
结构,否则将无法正常转换成JSON。这很乏味;如您所见,代码在每个可能的子类中几乎是逐字重复的。该run()
功能是没有问题的-这里的地方的魔力各种情况,这在每个阶级基础不同。
有没有一种方法可以将它拉到父类,而不必在转换为 JSON 之前明确指定要进行的转换类型?理想情况下,这可以根据get_report()
正在运行的实际类型来推断......
还有一个想法是使父类成为模板化类,它使用子报表类型作为模板参数:
#include <iostream>
#include <vector>
#include <memory>
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;
};
template<typename REPORT>
class Parent
{
public:
std::string get_report()
{
auto r = reports.back();
return r->type;
}
virtual void run() = 0;
protected:
std::vector<std::shared_ptr<REPORT>> reports;
};
class ChildA : public Parent<ChildAReport> {
public:
virtual void run() override
{
ChildAReport r;
r.foo = 1;
r.bar = 2;
reports.push_back(std::make_shared<ChildAReport>(r));
}
};
class ChildB : public Parent<ChildBReport> {
public:
virtual void run() override
{
ChildBReport r;
r.foo = 1;
r.baz = 3;
reports.push_back(std::make_shared<ChildBReport>(r));
}
};
int main()
{
auto ca = ChildA();
ca.run();
std::cout << ca.get_report() << std::endl;
auto cb = ChildB();
cb.run();
std::cout << cb.get_report() << std::endl;
return 0;
}
编辑答案,因为不再需要纯虚方法
更新您的评论:
为要在您的示例中使用的父类创建一个基类(接口):
class IGrandparent
{
public:
virtual std::string get_report() = 0;
virtual void run() = 0;
};
template<typename REPORT>
class Parent : public IGrandparent
{
public:
std::string get_report() override
{
auto r = reports.back();
return r->type;
}
protected:
std::vector<std::shared_ptr<REPORT>> reports;
};
int main()
{
std::unique_ptr<IGrandparent> childAInDisguise = std::make_unique<ChildA>();
std::unique_ptr<IGrandparent> childBInDisguise = std::make_unique<ChildB>();
childAInDisguise->run();
std::cout << childAInDisguise->get_report() << std::endl;
childBInDisguise->run();
std::cout << childBInDisguise->get_report() << std::endl;
return 0;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句