c++ - 用于设置相关类属性的 map 的合理键类型?

标签 c++

我打算编写一个代码,其中包含具有如下继承关系并具有与 Material 类型关联的各种属性的类:

  1. 抽象基类 Foo。没有与之关联的属性。
  2. Foo1GeneralElastic 继承自 Foo 类并具有与可能各向异性弹性 Material 相关的属性。
  3. Foo2GeneralElastic 也继承自类 Foo 并具有与 Foo1GeneralElastic 相同种类的 Material 属性,但在其他方面有所不同。
  4. Foo1PiezoElastic 继承自 Foo1GeneralElastic,具有压电特性和一般弹性特性。
  5. Foo1IsotropicElastic 继承自 Foo1GeneralElastic,但不共享其属性。

我决定抽象基类将有一个或多个方法采用 MyPropMap 类型的映射,定义为:

typedef std::map<PropertyLabel,std::vector<double> > MyPropMap

对于 PropertyLabel 类型可能有几种不同的选择,我正在尝试权衡每种选择的优缺点:

让 PropertyLabel 成为一个 enum:这将是轻量级的,但它基本上是一袋标签,用于我所使用的每种 Material 的所有不同属性考虑。

让 PropertyLabel 只是一个 int:在这里,我为每种 Material 类型准备了单独的头文件,每个头文件都包含静态整数常量的定义将是相关 Material 属性的标签。例如,MatPropKeyGenElastic.hpp 将定义整数常量 ELASTICITY_MATRIXMatPropKeyIsotropicElastic.hpp 将定义常量 ELASTIC_MODULUSPOISSONS_RATIOMatPropKeyPiezoElastic.hpp#include 文件 MatPropKeyGenElastic.hpp 并另外定义常量 PIEZO_CONST_MATRIX

棘手的事情是确保没有任何可以一起使用的常量具有相同的值。这可以通过使用将这些常量的值设置为唯一值的脚本生成头文件来实现。

让 PropertyLabel 成为 std::string 从这里我可以采取几种不同的方式。我可以在代码中使用像 "ELASTICITY_MATRIX" 这样的字符串文字,并依赖于这些文字永远不会被拼错——一个会在运行时而不是编译时捕获的错误。我可以用类似于上述整数常量方案的方式定义字符串常量,保持常量唯一性的任务很简单:只需将 ELASTICITY_MATRIX 的值设置为 "ELASTICITY_MATRIX"POISSONS_RATIO"POISSONS_RATIO" 的值,等等。

我看到的问题是,除了额外的开销之外,我已经看到了与非 POD 的全局静态常量相关的恐怖故事,例如主题 non-integral constants 中的评论中的故事。和 Defining class string constants in C++? .我想我可以将全局静态常量设置为 const char[] 数组,这些 POD 在用作映射键时会隐式转换为 std::string (而且,,我不打算让 map 键本身成为 const char*)。我还可以使用预处理器定义字符串文字,但我无法将它们保存在命名空间中。

您会推荐上述任何一种方法吗?它们中是否有我没有注意到的隐藏陷阱?您是否还有其他方法可以推荐?

最佳答案

我不推荐使用字符串。对于这样简单的任务来说太昂贵了。我投票给枚举。

但是如果将所有标签常量放在一个地方看起来太难看,您可以详细说明更复杂的方法 - 使用复合键,如两个数字对 -(类 ID,属性 ID)。

两者都可以定义为枚举,也许是嵌套的。此外,类 ID 可以自动生成 - 例如在 std::type_info 指针上使用 reinterpret_cast 或仅使用 std::type_info 指针或 std::type_index 如果支持的。用代码说明想法:

// PropertyLabel type, could be used as associative container key
struct PropertyLabel: std::pair<const std::type_info*, int>
{
  // Template ctor allows implicit conversion from enums
  // (actually not only from enums but from any int-compatible types)
  // Uncomment explicit keyword if implicit conversions scares you and use
  // explicit conversion syntax - PropertyLabel(smth).
  template <typename T> /*explicit*/ PropertyLabel(T label):
     std::pair<const std::type_info*, int>(&typeid(T), label)
  {
  }
};

// First property holder 
class PropertyUser1
{
public:
  enum Labels
  {
     eProperty1,
     eProperty2,
     eProperty3,
  };
 };

// Second property holder 
class PropertyUser2
{
public:
  enum Labels
  {
     eProperty1,// Due to class scope you could use same names for different properties
     eProperty2,
     eProperty3,
  };
 };

// Usage. A bit dangerous due to implicit conversions, but intuitive and handy:
MyPropMap properties;
properties[PropertyUser1::eProperty1].push_back(42.0);
properties[PropertyUser2::eProperty1].push_back(42.42);
// Will be with explicit ctor:
// properties[PropertyLabel(PropertyUser1::eProperty1)].push_back(42.0);
// properties[PropertyLabel(PropertyUser2::eProperty1)].push_back(42.42);

看起来它可以通过更多类型安全性来改进,从而消除使用非枚举类型(如 int)的可能性,例如禁用像 PropertyLabel(42) 这样的调用。但这只是为了说明想法。

关于c++ - 用于设置相关类属性的 map 的合理键类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12253613/

相关文章:

c++ - 总数中的特定数字

c++ - 是否有 STL 或 boost 函数来确定字符串是否为数字?

c++ - 如何使用 C++ 以编程方式检查您是否有实时互联网连接

c++ - 防止 C++ 类设计中的反馈路由

c++ - 需要关于 boost::mpl 的解释

c++ - 强制 C++ 更喜欢带有隐式转换的重载而不是模板

c++ - 如何在任务组中等待 Intel TBB 中的单个任务并杀死其他任务?

c++ - 使用 EasyBMP 库编译错误

c++ - 基于 SFINAE 的特征来确定是否支持运算符 +

android - 如何对位图图像应用灰度效果?