1

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

我不知道如何简短地描述这种情况,但我会尽力而为,希望它有意义。

问题是处理两条曲线,每条曲线都由一个或多个相同或不同曲线类型的段组成。因此,我开始为曲线段创建一个接口,其中包含将与之交互的曲线的模板类(例如,函数与两个不同曲线段之间的交点具有相同的类型):

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> { //... }

之后,我有一个 class 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
}

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

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

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

cell_base类中,其中的实现cell可以提取另一条曲线的适当段,并向其附加一个新单元格。例如,如果曲线abwherea表示网格中的 x 轴,并且我们要向曲线添加另一个曲线段a,我们可以找到网格的右侧大多数单元格,提取每个此类单元格的 y 轴上的曲线, 并从中和新提供的段创建一个新单元格,该单元格将附加到它是正确的。

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

将模板移动到cell_base类也行不通,因为这意味着在每次cell分配时我必须知道 next 的类型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必须是类型curve,它必须实现curve_segment<curve1>segment_y也有执行curve_segment<curve>

编辑2:解释为什么演员在那里

图片

以非粗体矩形为例。在这种情况下,有两条曲线,a2 段曲线b和 3 段曲线。classline也必须实现curve_segment<line>curve_segment<circle>而 circle 也必须同时实现。现在让我们将另一个贝塞尔曲线段添加到 curve a。类bezier必须实现curve_segment<line>and curve_segment<circle>,并且lineandcircle必须实现curve_segment<bezier>

让我们看看我们如何创建粗体三的中间部分cells。我们会打电话

add_curve_x<bezier>(new bezier(...));

在类型的单元格对象上cell<circle, circle>

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

4

1 回答 1

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>(...);
}
于 2012-10-18T15:01:11.737 回答