自动将父类中的 shared_ptr 向下转换为子类类型

slhck

我有一个虚拟父类,用于收集带有关联报告结构的报告。报告应该最终呈现为 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结构到实际ChildAChildB结构,否则将无法正常转换成JSON。这很乏味;如您所见,代码在每个可能的子类中几乎是逐字重复的。run()功能是没有问题的-这里的地方的魔力各种情况,这在每个阶级基础不同。

有没有一种方法可以将它拉到父类,而不必在转换为 JSON 之前明确指定要进行的转换类型?理想情况下,这可以根据get_report()正在运行的实际类型来推断......

RoQuOTriX

还有一个想法是使父类成为模板化类,它使用子报表类型作为模板参数:

#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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将 shared_ptr 转换为模板化类

将std :: shared_ptr <char>转换为std :: shared_ptr <unsigned char>

将shared_ptr <void>转换为shared_ptr <type>时智能指针的行为

这个shared_ptr如何自动转换为原始指针?

shared_ptr如何转换为私有基类?

删除器类型在unique_ptr与shared_ptr中

将'this'强制转换为std :: shared_ptr

将std :: shared_ptr <T>转换为void *

C++:将void指针转换为shared_ptr

无法将参数1从'std :: shared_ptr <ChaseState>转换为'std :: shared_ptr <State <Cow >>

将具有非const元素的shared_ptr的向量转换为具有const元素的shared_ptr的向量

将std :: shared_ptr隐式转换为指针类型

将sharet_ptr <Derived>转换为shared_ptr <Base>

将shared_ptr <Type>转换为weak_ptr <void>并返回

shared_ptr与unique_ptr在类和子类中的使用

是否可以将const unique_ptr引用(派生类)转换为shared_ptr(基类)

从enable_shared_from_this继承并返回self的shared_ptr的类的子类

有没有一种方法可以将模板的类型转换为shared_ptr <T>?

有没有一种方法可以将shared_ptr <void>转换为shared_ptr <T>?

将std :: map <int,std :: shared_ptr <Base >>转换为std :: map <int,std :: shared_ptr <Derived >>的最有效的安全方法

C ++ 11使用shared_ptr转换为向量和类

将“ this”称为shared_ptr?

如何使用shared_ptr在类型擦除类中显示基础数据

为什么我可以将0转换为std :: shared_ptr <T>而不转换为1?

使用A类类型的shared_ptr作为B类的成员变量

将标准库函数专门用于用户定义类型的shared_ptr是否合法?

shared_ptr增加父级引用

收到错误消息:名称空间“ std”中的“ shared_ptr”未命名类型

如何在C ++中的shared_ptr <FILE>到FILE *之间转换?