1

我正在编写矩阵类。看看这个定义:

template <typename T, unsigned int dimension_x, unsigned int dimension_y> 
class generic_matrix
{
  ...
  generic_matrix<T, dimension_x - 1, dimension_y - 1> 
  minor(unsigned int x, unsigned int y) const
  { ... }
  ...
}

template <typename T, unsigned int dimension> 
class generic_square_matrix : public generic_matrix<T, dimension, dimension>
{
  ...
  generic_square_matrix(const generic_matrix<T, dimension, dimension>& other)
  { ... }
  ...
  void foo();
}

generic_square_matrix 类提供矩阵乘法等附加功能。这样做没有问题:

generic_square_matrix<T, 4> m = generic_matrix<T, 4, 4>();

由于构造函数的原因,即使类型不是 generic_square_matrix,也可以将任何方阵分配给 M。这是可能的,因为数据不会跨子级更改,只会更改受支持的函数。这也是可能的:

generic_square_matrix<T, 4> m = generic_square_matrix<T, 5>().minor(1,1);

相同的转换适用于此。但是现在问题来了:

generic_square_matrix<T, 4>().minor(1,1).foo(); //problem, foo is not in generic_matrix<T, 3, 3>

为了解决这个问题,我希望 generic_square_matrix::minor 返回 generic_square_matrix 而不是 generic_matrix。我认为唯一可能的方法是使用模板专业化。但是由于专业化基本上被视为一个单独的类,所以我必须重新定义所有功能。我不能像调用派生类那样调用非专业类的函数,所以我必须复制整个函数。这不是一个很好的通用编程解决方案,而且需要大量工作。

C++ 几乎可以解决我的问题:派生类的虚函数可以返回与基类返回的不同类的指针或引用,如果这个类是从基类返回的类派生的。generic_square_matrix派生自 generic_matrix,但该函数不返回指针也不返回引用,因此此处不适用。

是否有解决此问题的方法(可能涉及完全不同的结构;我唯一的要求是尺寸是模板参数并且方阵可以具有附加功能)。

提前致谢,

路德

4

4 回答 4

4

您可以只在派生类中实现该函数而不使其成为虚拟函数。这将“隐藏”基类实现,尽管通常不喜欢隐藏成员函数,但您可能仍希望使用它。

更好的方法可能是只使用不同的名称,尽管这可能会破坏界面的“纯度”。

最后——minor() 可以实现为自由函数而不是成员函数吗?然后您可以根据需要提供重载,并在编译时调用正确的函数。这与我打开的方法隐藏案例最接近,但我怀疑它会被更普遍地接受为“良好实践”。

于 2010-05-26T16:56:55.273 回答
3

minor()如果您可以简单地制作一个免费功能,则无需使设计复杂化:

template<typename T, unsigned int X, unsigned int Y> 
generic_matrix<T, X-1, Y-1> 
minor(const generic_matrix<T, X, Y>& m, unsigned int x, unsigned int y);

...然后您可以根据需要添加替代版本。

于 2010-05-26T17:06:39.243 回答
1

如果您不以多态方式使用这些类型,则可以仅以非虚拟方式覆盖派生类中的基类方法,以便它返回派生类对象。它会隐藏通常不需要的基类版本,但在您的情况下似乎是这样。

或者,如果需要,可以使这些成员函数成为自由函数模板,并为不同类型的矩阵提供重载。(尽管模板化可能会自动解决这个问题。)

于 2010-05-26T17:07:14.473 回答
0

模板专业化将起作用。您所做的是获取共享代码并将其放入基类中,然后从两者继承。保护基础中的析构函数,这样没有人可以通过强制转换到基础并尝试删除它来破坏您的概念。

像这样:

namespace detail_
{
  template < typename T >
  struct my_templates_common_functionality
  {
    void f1() {}
    void f2() {}
  protected:
    ~my_templates_common_functionality() {}
  };
}

template < typename T >
struct my_template : detail_::my_templates_common_functionality<T>
{
  int f3() { return 5 }
};

template < >
struct my_template<double> : detail_::my_templates_common_functionality<double>
{
  char* f3() { return nullptr; }
};

还有其他方法,但这是最简单的方法之一。

于 2010-05-26T16:58:30.230 回答