- •Coursework thesis
- •Task for coursework
- •Abstract
- •List of abbreviations
- •Introduction
- •Domain analysis
- •Designing the system
- •Interface classes iSerializible, iEmissionable and iCloneable
- •Class for transport information
- •Bus, Plane, Train classes
- •Data storing. Transport schedule class
- •Array of pointers. Container class.
- •User Interface Design
- •Software implementation
- •Clock and Time classes.
- •Coordinates structure implementation
- •StationInfo structure implementation
- •IEmissionable, iSerializable and iCloneable implementation
- •TransportInfo class implementation
- •Bus, Plane, Train class implementation
- •TransportSchedule class implementation
- •Conclusions
- •References
- •Appendix a File Time.H
- •File Time.Cpp
- •File Clocks.H
- •File Clocks.Cpp
- •File iSerializable.H
- •File iEmissionable.H
- •File iCloneable.H
- •File stdafx.H
- •File stdafx.Cpp
- •CoordinatesData.Json
- •File transports.Csv
- •File Coordinates.Cpp
- •File main.Cpp
- •File Route.Cpp
- •File Route.H
- •File StationInfo. Cpp
- •File StationInfo.H
- •File TransportSchedule.H
- •File TransportSchedule.Cpp
- •File PtrArray.Cpp
- •File TransportInfo.Cpp
- •File TransportInfo.H
- •File Bus.H
- •File Bus.Cpp
- •File Plane.H
- •File Plane.Cpp
- •File Train.H
- •File Train.Cpp
- •Appendix b
User Interface Design
A user-friendly interface significantly increases the efficiency of the program. The interface should be intuitive so that users can easily enter starting points and destinations and quickly get route information. Interface should not crash in any reasons. Any incorrectly entered data must be checked and asked to be changed. The program should be consistent.
The interface will be implemented as simple outputtings from the console and inputtings into one. User will be able to choose what they need, and system administrator will as well manipulate the program but more ‘internally’. To get access to admin settings, you will need to know the password. All the data are checked, no incorrect input and always asking user to reenter data if an error occurs.
Software implementation
The primary objective of this project is to be said, hence the key considerations on project development can be made.
All classes of this work were created with adhering to principle of separation of class interface and its realization. That is, all classes have their .h and .cpp files.
As constructors of classes, where they are present, some methods of classes, methods for modifying and getting values of fields and most of operators’ overloads have pretty trivial realization, there aren’t described in very details in this section. As well as some methods and operators header files won’t be shown because of needless information it gives.
Full commented code of this program is placed in the Appendix A.
Clock and Time classes.
Time class is a parent class of Clocks. Time class must have fields hours, minutes, seconds with time_t data type, which is defined to store system time values returned by standard time() function and actually is just long long value. This data type was chosen to simply ease the understanding of Time class, i.e., when you have fields hours and moreover with type time_t it’s obviously for storing time. Time class also has virtual method to set time that takes three parameters and assigns them to correspond fields. Constructor of the class uses setTime method to set fields properly.
Time::Time()
{
Time::setTime(0, 0, 0);
}
and so with Clocks:
Clocks::Clocks(time_t h, time_t m, time_t s)
{
Clocks::setTime(h, m, s);
}
Since setTime is virtual method overridden in Clocks, the Time constructor calls Time::setTime() method, but for an instance of type Clocks, it calls Clocks::setTime(), although initially this is Time’s method. So, to avoid misunderstanding we explicitly show where whose method is called.
Discussed earlier, the parsing method to convert string to a Time object is listed below. Just handle the possible errors correctly and check if the obtained numbers are correct. That’s it.
bool Time::parseString(std::string_view str)
{
try
{
time_t hours, minutes, seconds;
std::stringstream ss(str.data());
char delimiter;
ss >> hours >> delimiter >> minutes >> delimiter >> seconds;
if (ss.fail() || !this->setTime(hours, minutes, seconds))
{
std::cerr << "Invalid parameters for time: " << str << '\n';
return false;
}
}
catch (std::exception const& e)
{
std::cerr << e.what() << '\n';
return false;
}
return true;
}
Besides those above, Time class as well contains getters, whose implementation we won’t discuss because there is nothing to say except it just returns value, overloaded operators +, whose implementation is below:
Time Time::operator+(time_t const value) const
{
Time tempTime;
time_t total_secs = this->total_secs() + value;
if (total_secs < 0)
total_secs = 0;
tempTime.setTime(total_secs / 3600, total_secs / 60 % 60, total_secs % 60);
return tempTime;
}
Operator ‘
’
uses this ‘
’
operator and the sets obtained values to the current object
instance.
Time Time::operator+=(time_t const value)
{
Time temp = this->operator+(value);
this->setTime(temp.hours, temp.minutes, temp.seconds);
return *this;
}
Then operators ‘
‘
and ‘
’
that simply change the value of ‘value’ to opposite one and use
the opposite operators ‘
’
and ‘
’
respectively.
Same operators but with other object won’t be showed because of their simplicity. Operators greater ‘>’, less ‘<’, greater or equal ‘>=’ and all these boolean operators do not need an explicit definition so we, as already was stated, define spaceship operator, which provides class with all these operators, to a default.
Last 2 disscussed operators will be output ‘<<’ and input ‘>>’ operators. Each of them has two overloads, for std::fstream objects and std::iostream. The implementation of operator ‘<<’ with std::ostream parameter uses <format> library to format a string to a type ‘hh:mm:ss’.
{
…
out << std::format("{:02}:{:02}:{:02}", other.hours,
other.minutes, other.seconds);
…
}
the ‘{:02}’ means "format the value as a 2-digit number, padding with leading zeros if necessary."
And operator ‘>>’ that checks input for correctness(for hours is below 24 value, minutes and seconds - below 60). But for my simplicity while developing project and for moduling purposes there was created a global function that corrects input for any value.
static void clearBuffer(std::istream& in)
{
in.clear();
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
template<typename Object, typename Function>
static void validateInput(Object& data, std::istream& in, Function foo, char const* text = "Incorrect input, try again: ")
{
while (true)
{
in >> data;
if (!foo(data) || in.fail())
{
clearBuffer(in);
std::cout << text;
}
else break;
}
}
template<typename Object>
static void validateInput(Object& data, std::istream& in, char const* text = "Incorrect input, try again: ")
{
while (true)
{
in >> data;
if (in.fail())
{
clearBuffer(in);
std::cout << text;
}
else break;
}
}
as can be seen the function has two overloads because there are situations when I do not need the predicate and just want to get correct value from some buffer. The first parameter of the function takes data to correct, second parameter is buffer which the data is taken from, third parameter is lambda boolean predicate with one parameter and last one is text to output into the console if the data is inputted incorrectly. So, now returning to our previous discussing, realization of ‘>>’ operator in Time class:
std::istream& operator>>(std::istream& in, Time& other)
{
std::string time_str;
std::cout << "Enter time in format hh.mm.ss: ";
validateInput(time_str, in);
if (!other.parseString(time_str))
in.setstate(std::ios::failbit);
return in;
}
