2015-08-12 2 views
0

Рассмотрим этот вывод:Виртуальные функции с различиями здесь и там

Current time: 6:30 pm 
Current time: 18:30 
Current time: evening. 
Current time: evening (for many it is dinner time, but many eat dinner later). 

Обратите внимание, что последние два имеют период, в то время как первые два не. Я получил этот желаемый результат с помощью функции System::displayCurrentTime члена из приведенной ниже коды:

#include <iostream> 
#include <string> 
#include <memory> 

class TimeDisplay { 
    public: 
     virtual std::string tell() const = 0; 
     virtual std::string tellMaybeWithPeriod() const = 0; 
}; 

class ClockDisplay12Hours : public TimeDisplay { // #1 
    std::string tell() const override {return "6:30 pm";} 
    std::string tellMaybeWithPeriod() const override {return tell();} 
}; 

class ClockDisplay24Hours : public TimeDisplay { // #2 
    std::string tell() const override {return "18:30";} 
    std::string tellMaybeWithPeriod() const override {return tell();} 
}; 

class DescriptiveTimeDisplay : public TimeDisplay { // #3 
    std::string tell() const override {return "evening";} 
    std::string tellMaybeWithPeriod() const override {return tell() + ".";} 
}; 

class CrazyDescriptiveTimeDisplay : public TimeDisplay { // #4 
    std::string tell() const override {return "evening (for many it is dinner time, but many eat dinner later)";} 
    std::string tellMaybeWithPeriod() const override {return tell() + ".";} 
}; 

struct System { 
    static std::shared_ptr<TimeDisplay> timeDisplay; 
    static std::string timeAsString() {return timeDisplay->tell();} 
    static std::string timeAsStringMaybeWithPeriod() {return timeDisplay->tellMaybeWithPeriod();} 
    // #3 and #4 will have a period, the others will not. 
    static void displayCurrentTime (std::shared_ptr<TimeDisplay> t) { 
     timeDisplay = t; 
     std::cout << "Current time: " << System::timeAsStringMaybeWithPeriod() << '\n'; 
    } 
    static void foo (std::shared_ptr<TimeDisplay>) {} // #1 and #3 will have a period, the others will not. 
    static void bar (std::shared_ptr<TimeDisplay>) {} // #1, #2, and #4 will have a period, the others will not. 
    static void baz (std::shared_ptr<TimeDisplay>) {} // #2 will have a period, the others will not 
}; 
std::shared_ptr<TimeDisplay> System::timeDisplay; 

int main() { 
    const std::shared_ptr<TimeDisplay> clocks[] = {std::make_shared<ClockDisplay12Hours>(), std::make_shared<ClockDisplay24Hours>(), 
     std::make_shared<DescriptiveTimeDisplay>(), std::make_shared<CrazyDescriptiveTimeDisplay>()}; 
    for (std::shared_ptr<TimeDisplay> t : clocks) 
     System::displayCurrentTime(t); 
} 

Это не очень грязное, но не отметить, что следующие функции для реализации foo, bar, baz хотят периоды с различными производными классами TimeDisplay, и на самом деле существует гораздо больше, чем 4 таких производных класса, а также более 3 новых функций-членов. Есть ли более элегантный и элегантный способ справиться с этими предстоящими функциями-членами, чем выписывать новые виртуальные функции для каждого из foo, bar, baz и т. Д., Вместе с которыми будет получать период, а какой нет? Как-нибудь использовать шаблоны (например, переименовать производные классы Derived<0>, Derived<1> и т. Д., А затем использовать эти целые числа компиляции, чтобы они соответствовали правилам, изложенным в комментариях выше)? Возможно, вы можете избежать шаблонов и сделать что-то еще?

+0

Просьба уточнить ваш вопрос. –

+0

Как лучше всего реализовать 'foo',' bar', 'baz' и т. Д., Следуя правилам, изложенным в комментариях выше, не повторяя беспорядка, создаваемого' displayCurrentTime'? В противном случае количество новых виртуальных функций будет взрываться. Я оставил 'foo',' bar', 'baz' пустым, потому что беспокоиться только о периоде бизнеса. – prestokeys

+0

Что случилось с помощью следующего кода: 'статической силы displayCurrentTime (станд :: shared_ptr т) { зЬй :: COUT << "Текущее время:" << t-> tellMaybeWithPeriod() << '\ п'; } ' –

ответ

1

Это можно сделать, предоставив параметр шаблона bool для четырех классов отображения часов. например

template <bool P> 
class DescriptiveTimeDisplay : public TimeDisplay { // #3 
    std::string tell() const override { return "evening"; } 
    std::string tellMaybeWithPeriod() const override { return tell() + (P ? "." : ""); } 
}; 
std::make_shared<DescriptiveTimeDisplay<true>>() 

для каждого из четырех функций displayCurrentTime, foo, bar, baz, вы можете контролировать свой формат отображение на инстанцировании четыре TimeDisplay дочерних классов с различными параметрами шаблона BOOL.

+0

@ simon Большое спасибо. Я опубликовал полное решение, основанное на вашей идее. Мета-программирование шаблонов дает идеальное решение, которое было типом решения, которое я подозревал и искал. – prestokeys

+0

@prestokeys: рад, что это помогает :-) – simon

0

Благодаря идее Симонова, теперь я получил идеальное решение, которое я хотел использовать следующие черты:

template <int, int> struct PeriodOrNoPeriod; 

template <> struct PeriodOrNoPeriod<0,0> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<0,1> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<0,2> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<0,3> : std::true_type {}; 

template <> struct PeriodOrNoPeriod<1,0> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<1,1> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<1,2> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<1,3> : std::false_type {}; 

template <> struct PeriodOrNoPeriod<2,0> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<2,1> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<2,2> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<2,3> : std::true_type {}; 

template <> struct PeriodOrNoPeriod<3,0> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<3,1> : std::true_type {}; 
template <> struct PeriodOrNoPeriod<3,2> : std::false_type {}; 
template <> struct PeriodOrNoPeriod<3,3> : std::false_type {}; 

и функцию для обработки всех случаев сразу:

template <System::Action A, int N> 
struct System::SetTimeDisplay { 
    static void execute (TimeDisplay::Mode mode) { 
     constexpr TimeDisplay::Mode M = static_cast<TimeDisplay::Mode>(N); 
     if (mode == M) 
      timeDisplay = std::make_unique<TimeDisplayClass<M, PeriodOrNoPeriod<A,M>::value>>(); 
     else 
      SetTimeDisplay<A, N+1>::execute(mode); 
    } 
}; 

template <System::Action A> 
struct System::SetTimeDisplay<A, TimeDisplay::NumTimeDiplayModes> { 
    static void execute (TimeDisplay::Mode) {} // End of recursion 
}; 

template <System::Action A> 
inline void System::action (TimeDisplay::Mode mode) { 
    SetTimeDisplay<A,0>::execute(mode); 
    finalAction<A>(); 
} 

Полного решения здесь:

http://ideone.com/6pET9E

Смежные вопросы