【问题标题】:Design pattern, a vector of objects, each of two possible types设计模式,对象向量,两种可能类型中的每一种
【发布时间】:2016-08-27 18:41:43
【问题描述】:

我需要在一个向量中存储恰好两种类型的对象,这两种类型几乎没有共同点。

将它们存储在向量中后,我想遍历该向量并执行操作,具体取决于类型。

到目前为止我的想法:

  • 多态性。矫枉过正,对我没有多大帮助,因为我可能会这样做:

    if(dynamic_cast<T1>() != nullptr) {
        ...
    } else {
       ...
    }
    
  • 合并两种类型(方法和字段)并添加一个布尔值,表示其类型是 1 还是 2。

这两种模式对我来说似乎都很笨拙,可能有一个完全简单的解决方案,我根本看不到。

第一种是这样的:

struct PatternMatch {
  int length;
  int indexInDict;
}

第二个 一:

struct NoMatch {
  std::string rawChars;
}

【问题讨论】:

  • 为什么不创建一个有 2 个成员变量的 class。一个是PatternMatch,第二个是NoMatch。然后创建一个包含该类对象的向量?
  • 如果你使用继承和虚函数,那么你不需要做任何dynamic_cast。事实上,这就是多态性的全部意义(而dynamic_cast 代表完全相反的方法)。
  • 为什么没有两个向量?
  • 我认为我们需要更多地了解您将如何处理这两种类型,以便希望找到一个优雅的解决方案。

标签: c++ design-patterns vector polymorphism


【解决方案1】:

使用boost::variant 或任何其他“基于堆栈的可区分联合容器”。我也建议visiting the variant using lambdas

// Either `A` or `B`.
using my_type = boost::variant<A, B>;

std::vector<my_type> my_vec;

// ...`emplace_back` stuff into `my_vec`...

auto visitor = make_lambda_visitor<void>(
    [](A&) { /* do something with A */ },
    [](B&) { /* do something with B */ }
);

for(auto& x : my_vec)
{
     boost::apply_visitor(visitor, x);
}

请注意,C++17 将有 std::variant

【讨论】:

  • 我虽然也谈到了访问者模式,但我唯一无法解决(微不足道)的问题是:我想在迭代集合时将两个连续的 NoMatches 合并为一个,但我没有说问题中的那个
【解决方案2】:

如果你知道你只有两种类型并且这个数字在未来不会增长,那么一个 C-ish 标记的联合就足够了并且易于使用:

struct PatternMatch {
  int length;
  int indexInDict;
};

struct NoMatch {
  std::string rawChars;
};

struct TaggedUnion {
  enum { MATCH, NO_MATCH } flag;
  union {
    PatternMatch match;
    NoMatch noMatch;
  };
};

现在,您可以创建TaggedUnions 的向量并检查flag 数据成员以找出每个元素的实际类型。

【讨论】:

  • 我现在避免了工会(有点害怕魔法)......但这似乎是我问题的解决方案
  • @J0hnD0e 联合背后确实没有魔法,有时它们很有用,为什么不呢? :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多