#include "Clock.h"
extern void appl(IClock&);
int main()
{
std::cout.setf(std::ios::boolalpha);
Clock c{};
appl(c);
}
#include <iostream>
#define SHOW(...)\
(void)(std::cout << __FILE__ << ':' << __LINE__ << '\t'\
<< #__VA_ARGS__ << " --> " << (__VA_ARGS__)\
<< std::endl)
#include "IClock.h"
void appl(IClock& c) {
SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(); SHOW(c);
c.Set(0, 0, 58); SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(); SHOW(c);
c.Set(0, 59, 58); SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(); SHOW(c);
c.TickUp(60); SHOW(c);
c.TickUp(600); SHOW(c);
}
#ifndef ICLOCK_H
#define ICLOCK_H
#include <iosfwd>
class IClock {
public:
virtual ~IClock() =default;
virtual void Set(int, int, int) =0;
virtual void TickUp(int = 1) =0;
virtual std::ostream& Print(std::ostream&) const =0;
};
inline
std::ostream& operator<<(std::ostream& lhs, const IClock& rhs) {
return rhs.Print(lhs);
}
#endif
#ifndef CLOCK_H
#define CLOCK_H
#include <iosfwd>
#include <cstring>
#include <iostream>
#include "IClock.h"
#include "LimitCounter.h"
#include "OverflowCounter.h"
class Clock : public IClock {
LimitCounter hours_;
OverflowCounter minutes_;
OverflowCounter seconds_;
public:
Clock(int hours = 0, int minutes = 0, int seconds = 0)
: hours_{24}
, minutes_{60, static_cast<ICounter&>(hours_)}
, seconds_{60, static_cast<ICounter&>(minutes_)}
{
Set(hours, minutes, seconds);
}
Clock(const Clock&) =delete; // copy c'tor
Clock& operator=(const Clock&) =delete; // copy assignment
Clock(Clock&&) =delete; // move c'tor
Clock& operator=(Clock&&) =delete; // move assignment
virtual void Set(int hours, int minutes, int seconds) override {
hours_.SetValue(hours);
minutes_.SetValue(minutes);
seconds_.SetValue(seconds);
}
virtual void TickUp(int seconds) override { seconds_.Count(seconds); }
virtual std::ostream& Print(std::ostream&) const override;
};
#endif
#include "Clock.h"
#include <iostream>
#include <iomanip>
std::ostream& Clock::Print(std::ostream& s) const {
std::ostream os{s.rdbuf()};
os.fill('0');
os << std::setw(2) << hours_.GetValue() << ':'
<< std::setw(2) << minutes_.GetValue() << ':'
<< std::setw(2) << seconds_.GetValue();
return s;
}
#ifndef ICOUNTER_H
#define ICOUNTER_H
class ICounter {
public:
virtual ~ICounter() =default;
virtual void Count() =0;
virtual void Reset() =0;
};
#endif
#ifndef COUNTER_H
#define COUNTER_H
#include <utility>
#include "ICounter.h"
template<typename Details>
class CounterBase : public ICounter, private Details {
private:
int value_{};
const int max_value_{};
using Details::WillOverflow;
using Details::WillReset;
using Details::HasOverflowed;
using Details::HasResetted;
public:
CounterBase(int max_value)
: value_{0}
, max_value_{max_value}
{}
template<typename T>
CounterBase(int max_value, T&& details_arg)
: Details{std::forward<T>(details_arg)}
, value_{0}
, max_value_{max_value}
{}
template<typename T1, typename T2>
CounterBase(int max_value, T1&& details_arg1, T2&& details_arg2)
: Details{std::forward<T1>(details_arg1), std::forward<T2>(details_arg2)}
, value_{0}
, max_value_{max_value}
{}
void SetValue(int value) { value_ = value; }
int GetValue() const { return value_; }
void Count(int amount);
virtual void Count() override final;
virtual void Reset() override final;
};
template<typename Details>
void CounterBase<Details>::Count(int amount) {
while (amount-- > 0) {
Count();
}
}
template<typename Details>
void CounterBase<Details>::Count() {
if (++value_ >= max_value_) {
WillOverflow();
value_ = 0;
HasOverflowed();
}
}
template<typename Details>
void CounterBase<Details>::Reset() {
WillReset();
value_ = 0;
HasResetted();
}
class LimitCounter_Details {
public:
void WillOverflow() {}
void WillReset() {}
void HasOverflowed() {}
void HasResetted() {}
};
using LimitCounter = CounterBase<LimitCounter_Details>;
#endif
#ifndef OVERFLOW_COUNTER_H
#define OVERFLOW_COUNTER_H
#include "LimitCounter.h"
class OverflowCounter_Details : protected LimitCounter_Details {
ICounter& next_counter_;
protected:
OverflowCounter_Details(ICounter& next_counter)
: LimitCounter_Details{}
, next_counter_{next_counter}
{}
void HasOverflowed() { next_counter_.Count(); }
void HasResetted() { next_counter_.Reset(); }
};
using OverflowCounter = CounterBase<OverflowCounter_Details>;
#endif
clock-6x:
g++ -std=c++14 *.cpp -o $@
run: clock-6x
./clock-6x
clean:
-rm -f *.o a.out core clock-6x
zip:
zip ../clock-6x.zip *.txt *.cpp *.h
Fill extension points via Template Base class (version 2)
---------------------------------------------------------
NOTE: All what is said for `clock-6` applies heres too – make
sure you read that other `README.txt` first.
TBD: describe perfect forwarding