代码之家  ›  专栏  ›  技术社区  ›  Ruud

派生的模板重写返回类型成员函数C++

  •  1
  • Ruud  · 技术社区  · 16 年前

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

    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();
    }
    

    一般的_square_matrix类提供额外的函数,如矩阵乘法。 这样做没问题:

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

    由于构造函数的原因,可以将任何平方矩阵赋给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++对我的问题几乎有一个解决方案:派生类的虚函数,如果基类返回基类返回的类,则可以返回一个指针或引用到一个不同于基类返回的类。通用方阵 是 派生自泛型_矩阵,但函数不返回指针或引用,因此此处不适用。

    有没有解决这个问题的方法(可能涉及到一个完全不同的结构;我唯一的要求是维度是一个模板参数,正方形矩阵可以有额外的功能)。

    事先谢谢,

    鲁德

    4 回复  |  直到 16 年前
        1
  •  4
  •   dash-tom-bang    16 年前

    您可以在派生类中实现该函数而不使其成为虚拟的。这将“隐藏”基类实现,并且可能是您所需要的,尽管一般不喜欢隐藏成员函数。

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

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

        2
  •  3
  •   Georg Fritzsche    16 年前

    如果你能简单地 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);
    

    …然后您可以根据需要添加其他版本。

        3
  •  1
  •   sbi    16 年前

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

    或者,如果需要的话,可以使用不同类型矩阵的重载使这些成员函数不受函数模板的约束。(尽管模板化可能会自动处理这个问题。)

        4
  •  0
  •   Edward Strange    16 年前

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

    就像这样:

    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; }
    };
    

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