Skip to content
Snippets Groups Projects
user avatar
tobiglaser authored
bd00998f
History

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 for hsrt.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 from Command which inherits from ICommand, but also from IDirection which also already inherits from ICommand. Maybe the class diagram could be simplified if ICommand would be replaced by the partially virtual Command. Commands
  • Gear, Pause and Direction 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 for Element because Command is now virtual and can no longer be use for the root Element.
  • CommandList and Element use template functions to allow adding multiple types of Commands. 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 and std::is_....
  • For variable types templates should use typename rather than class. Class vs Member variables
  • To call a static function without an object it is necessary to use the namespace operator MyClass::foo() rather than MyClass.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) uses std::make_shared<Command>(cmd) to produce a std::shared_ptr.
  • The destructor ~Element() may be configured to log destruction of removed Elements.

CommandList:

  • the Element root now is a shared_ptr<Element> and is initialized inline with std::make_shared<Element>(Command("root")). This is necessary because a shared pointer is empty upon construction.
  • All member functions previously returning Commands now return std::make_shared<Command>. This is to allow for returning nullptr if something went wrong.
  • getElement() now returns std::shared_ptr<Element>.
  • getPos() now returns std::make_shared<Command>.
  • Where appropriate the funtion parameter int has been replaced with unsigned int to prohibit passing negative values.
  • In add(Command cmd) std::make_shared<Element>(cmd) is used to create a new Element. Here is easily visible how std::make_shared() is the C++ equivalent to Java's new operator.
  • The std::bad_alloc-Exception possibly thrown by std::make_shared<Element>() is not catched in add(), to not introduce try{} catch{} too early. Thus add() wont return nullptr, 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