带有模板接口的C++多态性

C++ polymorphism with template interface

本文关键字:C++ 多态性 接口      更新时间:2023-10-16

Timer.h:

template<class T>
class Timer {
    public:
      typedef T Units;
    virtual Units get() = 0;
};

TimerImpl.h:

class TimerImpl: public Timer<long> {
public:
TimerImpl() {
}
~TimerImpl() {
}
long get();
};

FpsMeter.h(版本1):

template <class T> 
class FpsMeter {
    private:
    Timer<T>* timer;
    public:
    FpsMeter (Timer<T>* timer) {
        this->timer = timer;
    }
    ...
};

这个例子很有效。但它看起来并不漂亮。

Timer<long>* t = new TimerImpl();
FpsMeter<long>* f1  = new FpsMeter<long> (t);

这里有很多额外的模板使用。当类型是由实现定义的,而用户类不必定义新的类型,它应该使用实现的类型时,我如何实现这种多类型接口的想法。

如果你不介意一个总是在堆上创建FpsMeter的助手模板函数,你可以使用下面的

template < class T >
FpsMeter<T> *make_FpsMeter( Timer<T> *timer ) {
  return new FpsMeter<T>( timer );
  }

然后创建一个合适类型的FpsMeter就像一样

FpsMeter<long> *f1 = make_FpsMeter( new TimerImpl() );

或者,如果你可以使用C++11自动,你会得到

auto f1 = make_FpsMeter( new TimerImpl() );

据我所知,这是C++中能做的最好的一个。FpsCounter需要知道类型T,以便知道它可以接受哪些Timer<T>实现。您的示例代码可以稍微简单一些:

FpsMeter<long>* f1  = new FpsMeter<long> (new TimerImpl());

这至少可以避免重复模板类型,但在这种情况下,FpsMeter必须负责删除TimerImpl,最好是通过auto_ptr或类似的方式。

我也会质疑,是否真的需要更改get()的返回值。除了long之外,您希望它返回什么样的值?

也许您可以从C++11中的<chrono>库中获得灵感(也可以在boost中获得)。或者更好的是,节省一些时间,直接使用它。它高效、安全、灵活且易于使用。

如果你想只使用基于机器定时器实现的定时器(我认为应该在编译阶段为整个程序定义),我只需要使用typedef,也许还可以使用一些预处理器魔法:

[...]
#if TIMER_LONG // Here you should somehow check what type is used on target platform.
    typedef Timer<long> implTimer;
    typedef FpsMeter<long> implFpsMeter;
#else // If eg. using double?
    typedef Timer<double> implTimer;
    typedef FpsMeter<double> implFpsMeter;
#fi

这应该让用户代码不知道实际使用的类型,只要它使用implTimer和implFpsMeter。

如果你的意思是代码的某些部分将使用不同的TimerImpl,那么你应该使你的FpsMeter类多态

class FpsMeter{
public:
    virtual double fps()=0;
    virutal void newFrame()=0;
    [...]
    //Class counts new frames and using internal timer calculates fps.
};
template <typename T>
class FpsMeterImpl: public FpsMeter{
    TimerImpl<T>* timer;
public:
    FpsMeterImpl(TimerImpl<T>* timer);
    virtual double fps();
    virutal void newFrame();
};