【问题标题】:C++ combine maps of enumsC++ 组合枚举映射
【发布时间】:2021-10-29 18:54:55
【问题描述】:

假设我有一些游戏的类层次结构。像这样: PhysicalObjectBaseUnit 的父级 是 BaseArcher 的父级,依此类推... 每个层级都会添加自己的统计信息。

任何 PhysicalObject - 具有速度和大小。 任何 BaseUnit - 生命值。

我希望它用作枚举,所以:

enum class PhysicalObjectStats { speed, size };
enum class BaseUnitStats { hitpoints };

当然,BaseArcher 必须包含 PhysicalObject 和 BaseUnit 的统计信息。 如何制作这样的架构? 我试图以一种简单的方式实现它,只使用映射和动态多态性,但它不能编译(老实说,这是有充分理由的):

https://coliru.stacked-crooked.com/a/8496247abd3e6f41

另外,我尝试创建一个特定的 StatsHolder 类并且它可以工作,但在所有可能的用例(设置和获取值)中看起来都很糟糕。实际上,如果不进行向下转换,我就无法在课堂之外获得价值:

https://coliru.stacked-crooked.com/a/46f4f4aec6a22c57

另外,我的stats可能不止int,还有bool等一些类型。我尝试为它们使用 std::variant 并且效果很好,但我不想考虑它,使用“GetStats()”方法。所以,理想情况下我希望有这样一个界面:

std::shared_ptr<PhysicalObject> unit = std::make_shared<BaseUnit>();
unit->SetValue<int>(PhysicalObjectStats::speed);
std::cout << unit->GetValue<bool>(BaseUnitStats::HasArmor);

这让任务变得更加困难。关于如何以一种好的方式完成它的任何建议?

【问题讨论】:

标签: c++ c++11 enums


【解决方案1】:

我没有看到 map 和 enum 的意义,而普通成员似乎可以完成这项工作:

struct PhysicalObject
{
    int speed = 0;
    int size = 0;
};
struct BaseUnitStats : PhysicalObject
{
// or composition:
// physicalObject PhysicalObject;
    int hitpoints = 0;
};

对于您的StatsHolder 班级:

template<class StatsEnum>
struct StatsHolder
{
    void SetStats(StatsEnum stat, int value) { stats[stat] = value; }
    int GetStats(StatsEnum stat) const { return stats.at(stat); }
private:
    std::map<StatsEnum, int> stats;
};

派生类必须使用using:

struct BaseUnit : PhysicalObject, StatsHolder<BaseUnitStats> {
    using PhysicalObject::GetStats;
    using StatsHolder<BaseUnitStats>::GetStats;
    using PhysicalObject::SetStats;
    using StatsHolder<BaseUnitStats>::SetStats;

    BaseUnit() { SetStats(BaseUnitStats::hitpoints, 300); }
};

Demo

【讨论】:

  • 关于普通会员:如您所知,可能有很多统计数据,比如说 - 几十个。对于他们每个人,我至少必须提供一个 setter 和 getter。还有 - 完美 - 像“OnSetSpeed(int oldValue)”这样的方法。所以我的每一堂课都会被这样简单而单调的方法填满。使用枚举映射可以只使用一种“控制方法”。这是我的主要想法。
  • 另外,感谢您对“使用”的建议!它工作得很好,但是它本身需要用作对象,对吗?所以,我必须实现一些东西来将 PhysicalObject 的 ptr 转换成一些东西。例如,正如stackoverflow.com/a/32172486/10038365 中所述。
  • 如果你有一个PhysicalObject 指针并使用BaseUnit,你确实必须以某种方式强制转换它。但这似乎与您的 enum/map 问题无关。
  • “我必须提供一个 setter 和 getter”,只要这个公共成员就足够了。 “像OnSetSpeed(int oldValue) 这样的方法。” 这里有一个带有getter/setter/OnSet 信号的类property&lt;T&gt; 似乎也可以完成这项工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多