C++通过模板进行混入:为什么这不起作用?

发布于 2024-09-07 05:41:33 字数 1312 浏览 6 评论 0原文

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

例如:

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

I've got a interface that's implemented as an abstract base class with a number of pure virtual public methods. These pure virtual functions can be implemented using a template since the differences between subclasses aren't large - so my idea was to use multiple inheritance to mix-in the appropriately templated helper-class that provides the implementation. However, the compiler complains that the base class is abstract; it isn't considering the helper mix-in's implementation so thinks there's no implementation of a required method.

For example:

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

I'm using MSC 10.0 (Visual Studio 2010); the code fails with a similar error using g++ 4.5.

Get or the real-world equivalents in my project cannot be virtual because they're extremely minor operations that need to be inlined for adequate performance (think put-pixel/get-pixel) - so I need the generic algorithms to be templated rather than generic via virtual function calls.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沉睡月亮 2024-09-14 05:41:33

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

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

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

For implementing mix-ins via templates, you need the template implementing the abstract function to derive from the abstract base class.

So you may fix your code by changing it the following way:

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

// ...
class IndexableList : public AverageHelper<IndexableList> {

In general, if you want to provide more than one mix-in, you may either use a virtual inheritance in order not multiplying the instances of the base classes, or to use chain inheritance as in the following sample:

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
};
祁梦 2024-09-14 05:41:33

它不起作用,因为 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 {
  // ... 
};

It doesn't work because AverageHelper<>::Average() doesn't override TrivialList::Average(). In order to override a virtual function, the overriding class must inherit from the class containing the function to be overridden.

You could change your template thus:

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) {}
  // ...
};

You might want to virtually derive from TrivialList:

template<typename TIndexable, typename Base > 
class AverageHelper : virtual public Base {
  // ... 
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文