代码之家  ›  专栏  ›  技术社区  ›  Eamon Nerbonne

C++通过模板混合:为什么不工作?

  •  3
  • Eamon Nerbonne  · 技术社区  · 14 年前

    我有一个接口,它是作为一个抽象的基类实现的,带有许多纯虚拟公共方法。这些纯虚拟函数可以使用模板实现,因为子类之间的差异不大——所以我的想法是使用多个继承来混合提供实现的适当模板化的助手类。然而,编译器抱怨基类是抽象的;它没有考虑helper混合的实现,所以认为 实现所需的方法。

    例如:

    class TrivialList {
        int count;
    public:
        TrivialList(int count) : count(count){}
        virtual double Average() const=0;
        int Count() const {return count;}
        virtual ~TrivialList(){}
    };
    template<typename TIndexable> class AverageHelper {
    public:
        double Average() const {
            TIndexable const & self = static_cast<TIndexable const &>(*this);
            double sum=0.0;
            for(int i=0;i<self.Count();++) sum += self.Get(i);
            return sum / self.Count();
        }
    };
    class IndexableList : public TrivialList, public AverageHelper<IndexableList> {
        std::vector<double> backend;
    public:
        IndexableList(int count) : TrivialList(count), backend(count) { }
        double & Get(int i) { return backend[i];}
        double const & Get(int i) const { return backend[i];}
    };
    IndexableList * MakeList() {return new IndexableList(5);} //error!
    //    cannot instantiate abstract class
    

    我使用的是MSC 10.0(Visual Studio 2010);使用G++4.5时,代码会因类似的错误而失败。

    Get 或者,我项目中的现实世界中的等价物不能是虚拟的,因为它们是非常小的操作,需要通过内联来获得足够的性能(想想put pixel/get pixel),所以我需要模板化的通用算法,而不是通过虚拟函数调用实现通用算法。

    2 回复  |  直到 14 年前
        1
  •  4
  •   sbi    14 年前

    它不起作用,因为 AverageHelper<>::Average() 不重写 TrivialList::Average() . 为了重写虚函数,重写类必须从包含要重写的函数的类继承。

    您可以更改模板,从而:

    template<typename TIndexable, typename Base > 
    class AverageHelper : public Base {
    public:
      template< typename T >
      AverageHelper(T arg) : Base(arg) {}
      // ... 
    };
    
    class IndexableList : public AverageHelper<IndexableList,TrivialList> {
    public:
      IndexableList(int count) : AverageHelper<IndexableList,TrivialList>(count) {}
      // ...
    };
    

    你可能想从 TrivialList :

    template<typename TIndexable, typename Base > 
    class AverageHelper : virtual public Base {
      // ... 
    };
    
        2
  •  5
  •   Jack Shainsky    14 年前

    为了通过模板实现混合输入,需要实现抽象函数的模板从抽象基类派生。

    因此,您可以通过以下方式更改代码来修复代码:

    // ...
    template<typename TIndexable> class AverageHelper : public TriviaList{
    
    // ...
    class IndexableList : public AverageHelper<IndexableList> {
    

    一般来说,如果要提供多个混合,可以使用虚拟继承来避免将基类的实例相乘,或者使用链继承,如下示例所示:

    class Abstract {
    public:
        virtual void foo() = 0;
        virtual void bar() = 0;
    };
    
    template<class Base>
    class FooImpl : Base {
    public:
        void foo() { /* default foo implementation */ }
    };
    
    template<class Base>
    class BarImpl : Base {
    public:
        void bar() { /* default bar implementation */ }
    };
    
    class Derived : public BarImpl<FooImpl<Abstract> > {
        // You have both foo() and bar() implementations available
    };