Computer Science 3 Lab Exercises C++
This repo documents the transition of the third Computer Science lab exercises from Java to C++. The Course is about programming concepts rather than a specific language.
Changes
Worksheet 2
Background
-
commandlib.h
was introduced as a stand in forhsrt.mec.controldeveloper.core.com.command
. For simplicity everything is defined in one header. - Diverging from the class diagram the other interfaces dont inherit from
ICommand
as that would leed to weird inheritance loops where e.g.Gear
inherits fromCommand
which inherits fromICommand
, but also fromIDirection
which also already inherits fromICommand
. Maybe the class diagram could be simplified ifICommand
would be replaced by the partially virtualCommand
. Commands -
Gear
,Pause
andDirection
use multiple inheritance to allow the use of interfaces. This is fine, but it should be good practice to inherit from one base class only and only virtual classes otherwise. CommandList: -
CommandList
now needs a default constructor forElement
becauseCommand
is now virtual and can no longer be use for the rootElement
. -
CommandList
andElement
use template functions to allow adding multiple types ofCommand
s. This sort of is compile-time polymorphism. - There is no checking if the template got the right type though. Possibly there is a solution using
static_assert
andstd::is_...
. - For variable types templates should use
typename
rather thanclass
. Class vs Member variables - To call a static function without an object it is necessary to use the namespace operator
MyClass::foo()
rather thanMyClass.foo()
. Doxygen - see Trivia
Worksheet 1
Element:
- In Element every mention of Element is replaced with
std::shared_ptr<Element>
. - Command cmd becomes
std::shared_ptr<Command>
. - In the constructor
Element(Command cmd)
usesstd::make_shared<Command>(cmd)
to produce astd::shared_ptr
. - The destructor
~Element()
may be configured to log destruction of removed Elements.
CommandList:
- the
Element root
now is ashared_ptr<Element>
and is initialized inline withstd::make_shared<Element>(Command("root"))
. This is necessary because a shared pointer is empty upon construction. - All member functions previously returning
Command
s now returnstd::make_shared<Command>
. This is to allow for returningnullptr
if something went wrong. -
getElement()
now returnsstd::shared_ptr<Element>
. -
getPos()
now returnsstd::make_shared<Command>
. - Where appropriate the funtion parameter
int
has been replaced withunsigned int
to prohibit passing negative values. - In
add(Command cmd)
std::make_shared<Element>(cmd)
is used to create a newElement
. Here is easily visible how std::make_shared() is the C++ equivalent to Java'snew
operator. - The
std::bad_alloc
-Exception possibly thrown bystd::make_shared<Element>()
is not catched inadd()
, to not introducetry{} catch{}
too early. Thus add() wont returnnullptr
, but crash the program if an error occures.
Trivia
inline keyword
Although inline
can be used to influence performance, but this is
not how it should be used.
Much rather it can be used to deal with linking declarations over multiple translation units.
For variables it is a way to give the compiler "a place and a time" to initialize a static variable.
smart pointers
-
smart pointers point to NULL on construction.
-
They can easily be checked for content with
if (mySmartPointer) //has content else //is empty
-
A unique pointer will be destroyed at the end of it's scope.
-
A smart pointer will be destroyed when all of it's references are overwritten or the scope of the last reference ends.
std::optional or "return a value or null"
One task when implementing the linked list is to return the Command modified Element.
Or, if for whatever reason the operation fails to return null to signal an error to the user of the list.
This isnt possible right away in C++ as null cant be casted to any type.
To solve this problem in a concise and easy way std::optional<T>
was introduced in C++17.
It contains not only its given type T, but also a boolean to keep track if it is empty.
Example:
std::optional<Gear> opt = std::optional<Gear>(); // <- empty
opt = Gear(1, 2); // <- filled with value
if (opt)
cout << opt.value.getConfig();
else
cout << "is empty";
Doxygen
Basically Javadoc for C++ and many other languages.
Call doxygen -g
to generate a standard Doxyfile
Or doxygen -g my_conf
for a custom name
Then simply run doxygen
or doxygen my_conf
to execute.
CMake also allows to call doxygen as part of the build routine, see CMakeLists.txt
.
Basic settings in Doxyfile
:
- Project_name, _brief, _logo for project info
- Output_directory to specify a subfolder (here docs/)
- Optimize_output_for_C seems a good choice
- INPUT every directory or file to show up in the documentation (here src/ include/ README.md)
- RECURSIVE to also document subdirectories
- USE_MDFILE_AS_MAINPAGE because it would be empty otherwise (here README.md) (specify file in INPUT)
- SOURCE_BROWSER and INLINE_SOURCES for source code in documentation
- GENERATE_TREEVIEW for the sidebar well-known from Javadoc
- GENERATE_LATEX to spare generation of latex files