我正在编写矩阵类。看看这个定义:
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>();
由于构造函数,可以将任何方阵矩阵分配给M,即使类型不是generic_square_matrix。这是可能的,因为数据不会在子节点之间发生变化,只会受支持的功能。这也是可能的:
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,但该函数不返回指针或引用,因此这里不适用。
是否有解决此问题的方法(可能涉及完全其他结构;我唯一的要求是尺寸是模板参数,方形矩阵可以有其他功能)。
提前致谢,
路德
答案 0 :(得分:4)
您可以在派生类中实现该功能而不使其成为虚拟。这将“隐藏”基类实现,并且可能适合您的使用,尽管一般厌恶隐藏成员函数。
更好的方法可能是使用不同的名称,尽管这可能会破坏界面的“纯度”。
最后 - minor()可以实现为自由函数而不是成员函数吗?然后,您可以根据需要提供重载,并在编译时调用正确的函数。这是我打开的方法隐藏案例最接近的,但我怀疑它会被普遍认为是“良好做法”。
答案 1 :(得分: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);
...然后您可以根据需要添加替代版本。
答案 2 :(得分:1)
如果不以多态方式使用这些类型,则可以非虚拟地覆盖派生类中的基类方法,以便返回派生类对象。它会隐藏基类版本,这通常是不需要的,但在你的情况下它似乎是。
或者,您可以使这些成员函数使用自由函数模板,如果需要,可以使用不同类型矩阵的重载。 (虽然模板化可能会自动解决这个问题。)
答案 3 :(得分: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; }
};
还有其他方法,但这是最简单的方法之一。