【问题标题】:C++ class design: CovarianceC++ 类设计:协方差
【发布时间】:2015-02-01 15:11:57
【问题描述】:

问题

我想实现一些在图上工作的算法并返回节点对的分数,指示这些节点是否相似。这些算法应该适用于单个节点对和所有可能的节点对。在后一种情况下,应返回集合/矩阵。

我的方法

算法源自

class SimilarityAlgorithm {
public:
  Base(const Graph& G);

  virtual double run(node u, node v) = 0; // indices for nodes in the graph

  virtual ScoreCollection& runAll() = 0;
}

现在算法在内存使用方面有所不同。一些算法可能是对称的,并且 (u, v) 和 (v, u) 的分数是相同的。这需要返回不同的 ScoreCollection 类型。一个例子是一个稀疏矩阵和一个三角矩阵,它们都派生自ScoreCollection

这归结为协变返回类型:

class SpecificAlgorithm : SimilarityAlgorithm {
public:
  double run(node u, node v);

  // The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
  SymmetricScoreCollection& runAll();
}

问题

  • 这种设计方法是解决这个问题的好主意吗?
  • 是否应该公开集合都作为矩阵实现的事实?

【问题讨论】:

  • 您确定要按值获取节点吗?协方差的尝试应该会奏效。
  • 节点实际上只是 unsigned long 的 typedef。我认为在这种情况下按价值计算是可以的。
  • 当然,如果是这样的话,身份可能并不重要。
  • 如果功能相同,您可以将“SimilarityAlgorithm”作为类模板并传入“runAll()”所需的返回类型。

标签: c++ algorithm matrix class-design covariant


【解决方案1】:

您的设计似乎适合您描述的问题。

问题:

但是,您的 SpecificAlgorithm 存在问题:runAll() 没有返回与基类的虚函数相同的类型。所以它不会被调用(或者更可能的是,你的代码因为缺少虚函数而无法编译)。

解决方案:

通过使SymmetricScoreCollection 成为ScoreCollection 的派生类,对ScoreCollection 也使用多态方法:

class SymetricScoreCollection: public ScoreCollection {
//define the member functions to access the values virtual
...
}; 

class SpecificAlgorithm : public SimilarityAlgorithm {
public:
  double run(node u, node v);

  // The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
  ScoreCollection& runAll();
};    

其实它是factory method pattern的一个应用,具有以下作用:

  • SimilarityAlgorithm 是工厂,
  • SpecificAlgorithm 是具体工厂
  • ScoreCollection 是产品
  • SymetricScoreCollection 是具体产品

补充说明:

runAll() 返回对ScoreCollection 的引用会带来一些风险。假设sa 是一个特定的算法。

在下面的语句中:

ScoreCollection sc = sa.runAll();

sa.runAll() 返回对SymetricScoreCollection 的引用,但它会将引用的对象复制到 sc,使其成为 ScoreCollection。 Slicing 发生,多态性将无法工作。

但是,以下语句会成功:

ScoreCollection& rsc = sa.runAll();

因为 rsc 是一个引用,它仍然会引用 sa.runAll() 返回的原始 SymetricScoreCollection 对象,并且一切都会按设计工作。

您会发现,在返回引用时很容易出现未被注意到的错误。我建议返回一个指针而不是引用。

【讨论】:

  • 感谢您的回答。您如何看待 runAll()rvalue 引用 返回到成员对象?这将允许调用者从算法中窃取对象。我没有提到它,但我不希望算法实际存储来自runAll() 的结果。在一个完美的世界里,我想按值返回,并使用返回类型的协方差。有没有办法实现类似的东西?
  • 在这种情况下,您可以定义您的集合以使用 shared_ptr 元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多