3

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

例如:

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) - 所以我需要模板化的通用算法而不是通用的通过虚函数调用。

4

2 回答 2

5

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

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

// ...
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
};
于 2010-06-22T11:17:50.520 回答
4

它不起作用,因为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 {
  // ... 
};
于 2010-06-22T11:16:56.947 回答