online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#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) { 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(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
#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; }
#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; }
clock-2: g++ -std=c++14 *.cpp -o $@ run: clock-2 ./clock-2 clean: -rm -f *.o a.out core clock-2 zip: zip ../clock-2.zip *.txt *.cpp *.h
Adding an interface to the clock ================================ Adding an interface (class) `IClock` makes the design more flexible. Among other things several different types of clocks (with different counter arrangements) may implememt this interface. It is not shown in this solution, as simply moving all of the former member functions of clock to the `IClock` interface is disputables: It defeats at least one of the design goals, if is to operate clocks with a different number of counters over that interface.
To advance to the next step apply the following changes: * Improve the design by avoiding the need to have a data member `next_counter_` in the counters when it is not needed (ie. in the last counter of the chain): * implement one class `LimitCounter` * handling the reset logic in its `Count` member function * but does NOT allow to chain to a next counter stage; * from that derive a class `OverflowCounter` which calls the base class member function `LimitCounter::Count` for the reset logic but once it detects when a reset takes place and then forwards the carry. * As there is always a next counter stage, instead of a pointer a reference can (and should) be used to connect to it. NOTE: For an easier start here are the skeletons of the two classes: class LimitCounter { private: int value_; int max_value; public: LimitCounter(int max_value) : value_{0} , max_value_{max_value} {} ... }; class OverflowCounter : public LimitCounter { private: LimitCounter& next_counter_; ... public: OverflowCounter(int max_value, LimitCounter& next_counter) : LimitCounter{max_value} , next_counter{next_counter_} {} ... }; * The "hint" whether a reset took place, required should may * EITHER be given by a `bool` return value of `LimitCounter::Count` which then is tested in `OverflowCounter::Count` * OR by testing the base class counter value. NOTE: For an easier start here are the skeletons how the two `Count` member functions might be implemented. // EITHER (first solution) that is the way to go: bool LimitCounter::Count() { ...increment counter... if ( ...test whether limit is reached, if so ...) { ... reset value to 0 ... return true; } return false; } // then override (and reuse) the inherited implementation bool OverflowCounter::Count() { if (LimitCounter::Count()) { next_counter_.Count(); return true; } return false; } // ALTERNATIVELY (second solution) that is the way to go: void LimitCounter::Count() { ...increment counter... if ( ...test whether limit is reached, if so ...) { ... reset value to 0 ... } } // then override (and reuse) the inherited implementation void OverflowCounter::Count() { LimitCounter::Count(); if (LimitCounter::GetValue() == 0) { // obviously a reset occured next_counter_.Count(); } } * Do similar changes for the `LimitCounter::Reset`: * simply set the counter value to `0` * And to `OverflowCounter::Reset`: * call the inherited implementation, * then reset the chained counter. ================================================================= Optional: * Make sure you understand the design and especially why * with three or more counters in the chain it is ESSENTIAL to use late binding (= `virtual` member functions) for `LimitCounter::Count` and `LimitCounter::Reset`, * while with only two counters (ie. a single `OverflowCounter` connected to a single `LimitCounter` it would work without. * Furthermore, comparing the new designawith a base and a derived class to the previous pointer-based solution with a single class, which made a decision whether there is a next counter in the chain in a conditional statement ... if (next_counter_ != nullptr) next_counter_.Count(); ... to WHERE is this test gone now? How does the equivalent branch in the control-flow – that is still necessary(!) – happen?

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue