C ++ полиморфизм с шаблоном интерфейса - PullRequest
1 голос
/ 01 февраля 2012

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

Здесь есть много дополнительных шаблонов.Как я могу реализовать эту идею интерфейса multy-type, когда тип определяется реализацией, а пользовательский класс не должен определять новый тип, он должен использовать тип реализации.

Ответы [ 4 ]

1 голос
/ 02 февраля 2012

Если вы не возражаете против вспомогательной функции шаблона, которая всегда создает 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, вы получите

auto f1 = make_FpsMeter( new TimerImpl() );
1 голос
/ 02 февраля 2012

Возможно, вы можете черпать вдохновение из библиотеки <chrono> из C ++ 11 (также доступна в boost).Или, что еще лучше, сэкономьте время и просто используйте его напрямую.Это эффективный, безопасный, гибкий и простой в использовании.

1 голос
/ 02 февраля 2012

Насколько я знаю, это лучшее, что вы можете сделать в C ++.FpsCounter необходимо знать тип T, чтобы он знал, какие реализации Timer<T> он может принять.Ваш пример кода можно сделать несколько проще:

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

... что по крайней мере избавит вас от повторения типа шаблона, но, конечно, в этом случае FpsMeter должен взять на себя ответственность за удаление TimerImpl, в идеале через auto_ptr или тому подобное.

Я бы тоже спросил, нужно ли вам действительно изменять возвращаемое значение get().Какие значения вы ожидаете получить, кроме long?

0 голосов
/ 02 февраля 2012

Если вы хотите использовать только таймеры, основанные на реализации машинного таймера (который должен быть определен на этапе компиляции для всей программы, я полагаю), я бы просто использовал 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

Это должно привести к тому, что пользовательский код не будет знать о фактическом используемом typee, если он использует 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();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...