C++ 结合枚举映射
C++ combine maps of enums
假设我有一些 class 游戏层次结构。像这样:
PhysicalObject 是 BaseUnit 的父级 BaseArcher 等等...
每个层级都会添加自己的统计信息。
任何物理对象 - 都有速度和大小。
任何 BaseUnit - 生命值。
我希望它被用作枚举,所以:
enum class PhysicalObjectStats { speed, size };
enum class BaseUnitStats { hitpoints };
当然,BaseArcher 必须包括 PhysicalObject 和 BaseUnit 的统计信息。
如何制作这样的架构?
我试图以如此简单的方式实现它,仅使用映射和动态多态性,但它无法编译(老实说,这是有充分理由的):
https://coliru.stacked-crooked.com/a/8496247abd3e6f41
此外,我尝试创建一个特定的 StatsHolder class 并且它有效,但在所有可能的用例(设置和获取值)中看起来都很糟糕。实际上,如果不向下转换,我无法在 class 之外获得价值:
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);
这使任务变得更加困难。关于如何以好的方式完成它有什么建议吗?
我看不出 map 和 enum 的意义,而普通会员似乎可以做到:
struct PhysicalObject
{
int speed = 0;
int size = 0;
};
struct BaseUnitStats : PhysicalObject
{
// or composition:
// physicalObject PhysicalObject;
int hitpoints = 0;
};
为了你的 StatsHolder
class:
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;
};
派生 classes 必须使用 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); }
};
假设我有一些 class 游戏层次结构。像这样: PhysicalObject 是 BaseUnit 的父级 BaseArcher 等等... 每个层级都会添加自己的统计信息。
任何物理对象 - 都有速度和大小。 任何 BaseUnit - 生命值。
我希望它被用作枚举,所以:
enum class PhysicalObjectStats { speed, size };
enum class BaseUnitStats { hitpoints };
当然,BaseArcher 必须包括 PhysicalObject 和 BaseUnit 的统计信息。 如何制作这样的架构? 我试图以如此简单的方式实现它,仅使用映射和动态多态性,但它无法编译(老实说,这是有充分理由的):
https://coliru.stacked-crooked.com/a/8496247abd3e6f41
此外,我尝试创建一个特定的 StatsHolder class 并且它有效,但在所有可能的用例(设置和获取值)中看起来都很糟糕。实际上,如果不向下转换,我无法在 class 之外获得价值:
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);
这使任务变得更加困难。关于如何以好的方式完成它有什么建议吗?
我看不出 map 和 enum 的意义,而普通会员似乎可以做到:
struct PhysicalObject
{
int speed = 0;
int size = 0;
};
struct BaseUnitStats : PhysicalObject
{
// or composition:
// physicalObject PhysicalObject;
int hitpoints = 0;
};
为了你的 StatsHolder
class:
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;
};
派生 classes 必须使用 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); }
};