虚拟模板功能解决方法

时间:2012-10-17 21:13:44

标签: c++ templates virtual-functions

我偶然发现了一个问题(我的任何知识渊博的同事都不知道)如何解决(解决问题)。最终的问题是无法创建虚拟模板功能。我彻底搜查了网,找到了几种处理它的方法,但似乎没有一种适用于我的情况。

我不知道如何描述这种情况,但我会尽我所能并希望它有意义。

问题在于处理两条曲线,每条曲线由一个或多个相同或不同曲线类型的段组成。所以我开始为曲线段创建一个界面,它将与曲线的模板类进行交互(例如,函数与两个不同曲线段之间的交叉点的类型相同):

template<class curve> class curve_segment { // some methods here }
然后,用户可以实现几种类型的曲线,以及适当的函数,具体取决于它将与之交互的曲线。例如,circleline,两者都可以与两者互动:

class line :  public curve_segment<line>, public curve_segment<circle> { //... }
class circle :  public curve_segment<line>, public curve_segment<circle> { //... }

接下来,我有一个类cell,它依赖于两个曲线段,以及一个封装它的基类cell_base

template<class curve1, class curve2> class cell : public cell_base { 
  cell_base* up; cell_base* down;

  curve_segment<curve1>* segment_x;
  curve_segment<curve2>* segment_y;

  // some methods that depend on both curves
}

最后,存在这样的单元的2D网格m * n,其中两条曲线由可能不同类型的m和n curve_segments组成,并且由每个单元中的两个指针保持在一起。

问题开始显示何时将新的curve_segment添加到两条曲线之一。显而易见的解决方案是添加

template<class curve> virtual void add_curve_x(curve_segment<curve> seg) =0;

cell_base类,cell中的实现可以提取另一条曲线的相应段,并向其中添加一个新单元格。例如,如果曲线ab a表示网格中的x轴,我们要将另一条曲线段添加到曲线a,我们可以找到在网格的大多数单元格的右侧,在每个这样的单元格的y轴上提取曲线,并从那里和新提供的分段创建一个新单元格,它将附加到右边。

类型擦除不起作用,因为我们需要知道cell创建时新添加的段的类型(我们需要将两个段的类型作为模板参数提供给{{ 1}} class)。

将模板移动到cell类也行不通,因为这意味着在每次cell_base分配时我都必须知道下一个cell的类型

有解决方法吗?

修改: 如建议的那样,添加curve_segment方法:

add_curve_x

在这种情况下,template<class curve1, class curve2> template<class curve> cell<curve1, curve>* cell<curve1, curve2>::add_curve_x(curve_segment<curve1>* seg) { return new cell<curve1, curve>(seg, (curve_segment<curve>*)(this->segment_y)); } 必须是seg类型,必须实现curvecurve_segment<curve1>还必须实施segment_y

编辑2 :解释为什么演员阵容

pic

以非粗体矩形表示。在这种情况下,有两条曲线,曲线curve_segment<curve>包含2个曲线,曲线a包含3个曲线。类b必须实现line以及curve_segment<line>,而circle也必须实现这两者。现在让我们将另一个贝塞尔曲线段添加到曲线curve_segment<circle>。课程a必须实施beziercurve_segment<line>,而curve_segment<circle>line必须实施circle

让我们看看我们如何创建粗体三curve_segment<bezier>的中间部分。我们打个电话

cells

add_curve_x<bezier>(new bezier(...)); 类型的单元格对象上。

参数cell<circle, circle>将是一个新的seg对象(可以转换为bezier),这也是curve_segment<circle>类型的内容,{{1必须转换为curve,因为这是它在新创建的单元格中与之交互的曲线类型。

1 个答案:

答案 0 :(得分:0)

添加curve_segment_base

class curve_segment_base {
   // for double dispatching here:
  virtual cell_base* add_curve_x(cell_base* cell) = 0;
};

template<class curve> 
class curve_segment : public virtual curve_segment_base { 
     // some specific methods here 
     // for double dispatching here:
     virtual cell_base* add_curve_x(cell_base* cell)
     {
         // this has to be moved to cpp file due to dependency from cell_base
         return cell->add_curve_x(this); // now the correct method from cell is called
     }
};

因此,您可以将此方法作为虚拟添加到您的cell_base

class cell_base {
   virtual cell_base* add_curve_x(curve_segment_base* seg) = 0;

   // methods necessary for double dispatching here:
   virtual cell_base* add_curve_x(curve_segment<line>* seg) = 0;
   virtual cell_base* add_curve_x(curve_segment<circle>* seg) = 0;
   ...
};

所以你的方法看起来像是双重调度:

template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment_base* seg) {
  return seg->add_curve_x(this);
}

您必须为所有细分实施所有真正的实施方法:

template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment<line>* seg) {
  return new cell<curve1, line>(...);
}
template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment<circle>* seg) {
  return new cell<curve1, circle>(...);
}