【问题标题】:A C++ issue with multiple inheritance, templates and static variables多重继承、模板和静态变量的 C++ 问题
【发布时间】:2016-12-14 14:13:10
【问题描述】:

我有一个类似下面的代码:

template<class ObjType>
class jsonable
{
 private:
    static map<string, jsonElem> config;
 protected:
    virtual void setConfig() = 0;
 //other fields and methods in public/private
}

class user : public jsonable<user>
{
 protected:
    virtual void setConfig();
 //other fields and methods in public/private
}

class client : user
{
 protected:
    virtual void setConfig() {user::setConfig(); /* more config */}
 //other fields and methods in public/private
}

这段代码的主要思想是在静态变量中保存与模板中引用的类相关的数据。当我想从用户类继承时,问题就来了:静态变量在用户类和客户端类之间共享,而不是每个类一个静态变量。

我尝试过类似的操作:

class client : user, jsonable<client>

但是出现了一堆问题(许多方法同名,还有一些与继承2次同一个类有关)。我不知道是否有一种优雅的方式来做到这一点,或者即使有办法。 (我是 C++ 的新手)

欢迎任何想法! :)。当然,我可以将用户的所有内容“复制”到客户端,但是......我不想这样做,直到没有更多选项。

编辑: 为了给问题添加上下文和细节,我将解释一下我在做什么(或想要做什么)。 Jsonable 是一个类,它提供了将另一个类序列化为 Json 的能力(由 https://github.com/nlohmann/json 提供帮助)。

为了实现这一点,它使用静态映射来存储每个 jsonable-field 名称及其信息(类型和相对于内存中类开始的位置,因此可以对其进行序列化和反序列化)。

如果一个类继承自另一个继承自 jsonable 的类,就会出现问题。两者都共享该映射,因此在序列化/反序列化时只考虑基类数据。希望这个解释有助于理解...

Edit2:在问题中提供完整代码对我来说似乎太过分了。如果有人想要编译一些东西,我已经上传了一个 git repo:https://github.com/HandBe/jsontests 非常感谢所有对此问题感兴趣的人!

【问题讨论】:

  • 也许是骗子,也许不是,但同样值得一读:How can I avoid the Diamond of Death when using multiple inheritance?
  • 如果你解释了你的类/子类的期望行为是什么,回答这个问题会更容易。
  • 如果你可以实现user而不从jsonable&lt;user&gt;派生,那么解决你的问题就很容易了。
  • 请确保不要忘记实际代码中的虚拟 ~dtors。
  • 无法调试不可见的代码。请演示一个可以被其他人复制的特定问题,如minimal reproducible example 中所述。

标签: c++ templates c++11 inheritance static-variables


【解决方案1】:

一个可能的解决方案可以从user(因为它是一个用户)和jsonable&lt;client&gt;作为(私有/公共分开)派生出client

class user : public jsonable<user>
{
 protected:
    virtual void setConfig();
 //other fields and methods in public/private
};

class client: public user, public jsonable<client>
{
   virtual void setConfig()
   {
       user::setConfig();
       // more config, referred to jsonable<client>::map
   }
}

因为它必须为自己实现 jsonable(不管user)。

这是所谓的“堆叠平行四边形”继承模式,在多个接口实现中作为模块化行为非常常见。

现在用户和客户端都有自己的配置

【讨论】:

  • 我已经在其中工作了半天左右。我仍然坚持,因为它似乎是最好的选择(当然就像@grek40 说它不适用于虚拟继承,但我相信可以做点什么)。此实现的实际状态:github.com/HandBe/jsontests
  • 终于成功了!我必须添加许多解决方法,例如新函数virtual void setConfig(map&lt;string, json::jsonElem&gt; &amp;config) 将静态传递给基类,因此基类可以在上层信息中“注册”其信息。谢谢! PD:可能,我会在完全验证后将其开源。谢谢大家~!
  • 它不能与虚拟继承一起使用:jasonable&lt;user&gt;jasonable&lt;client&gt; 是不同的东西,不能合并(也不能合并)
【解决方案2】:

如果我正确理解了您的问题:您希望 client 成为 user,但还要在 jsonable 中定义所有每个类的静态?

您是否考虑过组合而不是继承?这两种方式都可以:

1) 使user 成为客户端的组件

class client : public jsonable<client>
{
    user parent; // could also be a pointer
    void setConfig() {parent.setConfig(); /* more config */}
    /* ... */
}

2) 使jsonable 成为一个组件:

class user
{
    jsonable<user> userjson; // public, private, whatever is appropriate for your design
    /* ... */
}

class client : public user
{
    jsonable<client> clientjson;
    /* ... */
}      

【讨论】:

  • 谢谢@Joris。我当然考虑过,当然也可以是最后的选择。这个实现的问题是我不能创建一个不同用户的列表。当然,如果我没有找到更好的选择,我会接受!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
相关资源
最近更新 更多