#include "Clock.h"
#include <iostream>
#define SHOW(...)\
(void)(std::cout << __FILE__ << ':' << __LINE__ << '\t'\
<< #__VA_ARGS__ << " --> " << (__VA_ARGS__)\
<< std::endl)
int main()
{
std::cout.setf(std::ios::boolalpha);
Clock 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.TickUp(60); SHOW(c);
c.TickUp(60); SHOW(c);
Clock c2{23, 59, 58}; SHOW(c2);
c2.TickUp(); SHOW(c2);
c2.TickUp(); SHOW(c2);
c2.TickUp(); SHOW(c2);
}
#ifndef CLOCK_H
#define CLOCK_H
#include <iosfwd>
#include "Counter.h"
class Clock {
Counter hours_;
Counter minutes_;
Counter seconds_;
public:
Clock(int hours = 0, int minutes = 0, int seconds = 0)
: hours_{24}
, minutes_{60, &hours_}
, seconds_{60, &minutes_}
{
Set(hours, minutes, seconds);
}
Clock(const Clock&) =delete;
Clock& operator=(const Clock&) =delete;
void Set(int hours, int minutes, int seconds) {
hours_.SetValue(hours);
minutes_.SetValue(minutes);
seconds_.SetValue(seconds);
}
void TickUp(int ticks = 1) { seconds_.Count(ticks); }
friend std::ostream& operator<<(std::ostream&, const Clock&);
};
#endif
#include "Clock.h"
#include <iostream>
#include <iomanip>
std::ostream& operator<<(std::ostream& lhs, const Clock& rhs) {
std::ostream os{lhs.rdbuf()};
os.fill('0');
os << std::setw(2) << rhs.hours_.GetValue() << ':'
<< std::setw(2) << rhs.minutes_.GetValue() << ':'
<< std::setw(2) << rhs.seconds_.GetValue();
return lhs;
}
#ifndef COUNTER_H
#define COUNTER_H
class Counter {
private:
int value_{};
const int max_value_{};
Counter* next_counter_{};
public:
Counter(const Counter&) =delete;
Counter& operator=(const Counter&) =delete;
Counter(int max_value, Counter* next_counter = nullptr)
: value_{0}
, max_value_{max_value}
, next_counter_{next_counter}
{}
auto SetValue(int value) { value_ = value; }
auto GetValue() const { return value_; }
void Count(int amount = 1);
void Reset();
};
#endif
#include "Counter.h"
void Counter::Count(int amount) {
while (amount-- > 0) {
if (++value_ >= max_value_) {
value_ = 0;
if (next_counter_) {
next_counter_->Count(1);
}
}
}
}
void Counter::Reset() {
value_ = 0;
if (next_counter_) {
next_counter_->Reset();
}
}
Example For a Clock Build From a Helper Class `Counter`
=======================================================
The overflow algorithm is separated into a class of its own.
Objects of this class can be chained via pointers. The last
in the chain holds a null pointer.
PRO-s:
straight forward extension
still quite easy to understand
CON-s:
no flexibility wrt. the counters used in the clock
UNRELATED improvements:
Output (designed mostly for debugging and prove of concept)
moved into helper macro.
PRO-s:
more compact
centralizes changes and extensions
CON-s:
to understand the program the helper macro needs to
be understood too
To advance to the next step apply the following changes:
* Add an interface `IClock` through which several kinds of clocks
may be operated, eg.:
* an `HHMMSS_Clock` counting hours, minutes, and seconds (ie.
as the previous `Clock` did);
* a `Stopwatch` counting microseconds up to 999 and (unlimited)
seconds.
* am "operating hours meter" counting days (unlimeted), hours
and minutes.
NOTE: You do not necessarily need to implement another clock but
stay with the current (single) clock. But in that case at
least show that you can create a `Clock` object in `main`
and hand it over to a function `appl` accepting and
`IClock&` argument.
* Setup the project to consist of header files and separately
compiled source filess (= implementation files).
* minimize referencing headers from implementations;
* if necessary use forward declarations (or maybe introduce
forwarding headers).
=================================================================
Optional:
* Discuss ways to easily provide "unlimited" counters.
* How could "permanent overflow indicators" be added to the last
counter stage, indicating that the whole chain had overlown at
least once?
* Discuss the problem of the `Set` member function, which may
require a different number of arguments depending on the number
of `Counter`-s used in that kind of clock implementation.
NOTE: If time allows, feel free to implement some of the features
only discussed/suggested above.
all: main run
run: main
./main
main: *.cpp *.h
g++ -std=c++14 *.cpp -o $@
clean:
-rm -f *.o a.out core main
zip: clean
zip ../clock-01.zip *.txt *.cpp *.h Makefile
.PHONY: all run clean zip