cpp2022W17
MicroConsult C++ 2022 KW 17
Wie am letzten Kurstag angekündigt, werde ich "zum Nachlesen" demnächst nochmal ein ZIP-Archiv bereitstellen, in dem alle Mosterlösungen inklusive der verbindenden Live-Demos enthalten sind, durchnummeriert in der Reihenfolge der Behandlung im Kurs.
Eine Anregung aus dem Feedback zum Kurs habe ich darin schon umgesetzt: Die Beispiele zur "C/C++-Kompatibiliät" und zum praktischen Vorgehen bei einem "C nach C++"-Umstieg in bestehenden C-Projekten habe ich ausgegliedert. D.h. dieser Teil wird sich künftig nur als optionales Kapitel im Anhang der Unterlagen befinden.
Die Aufgaben des Praktikums werden dann mit einem "reinen" C++-Beispiel beginnen.
Ich wünsche Ihnen ein Schönes Wochenende,
Stand der Aufgaben und Lösungen Donnerstagmittag
https://drive.google.com/file/d/12bVCSK-gUUKYz7JPfIsA1YLihQJkW4_G/view?usp=sharing
https://onlinegdb.com/6pSK8qelM
https://onlinegdb.com/94ViqDdXc
https://onlinegdb.com/NM2-CrgYqP
Auch interessant: http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
Link zure letzten Übung: https://onlinegdb.com/vX7ndMZwl
LATEST ARCHIVE: https://drive.google.com/file/d/1EeiluKrgH0LfodrapYIBuUzOR0mg_7Tm/view?usp=sharing
https://onlinegdb.com/zZRCkIdexp
https://drive.google.com/file/d/1Zkeb3JJQ7HV4-H4J_fJDo5t0SyAgyXy8/view?usp=sharing
- Link zum Demo-Beispiel "swap" (Pointer vs. Referenzen):
https://godbolt.org/z/s5W3nc1xr
# 1_Counter Overview
## Step_00
Goals:
* Establish common base with C knowledge as prerequisite
* Motivate separation into separate compilation units
Introduces:
* Compilation environment
## Step_01
Prepared:
* added "Test Driven Development" (TDD)
* added "Command Line Interacttion" (CLI)
### Main Stream -> Step_02
Goals:
* Allow compiling with both, C an C++.
Introduces:
* Strict "Definition Reference Model"
* Clean use of `enum` types
* Necessity of casts from `void*` to typed pointers
### Variants (not continued)
* Step_01x: do NOT cast away `const` from global variables
* Step_01y: ... though it usually works for stack variables
* Step_01z: C-Preprocessor trickery (not really recommended)
## Step 02
(Compiles cleanly with C **OR** C++ used for **ALL** modules)
### Main Stream -> Step_03
Goals:
* Make more flexible with additional global variable `limit`.
Introduces:
* Use of `const` for globals
### Variants (not continued)
* Step_02x: Mix modules compiled with C and C++
## Step_03
(Flexible upper limit via global variable)
### Main Stream -> Step_04
Goals:
Combine global variables `counter` and `limit` into ADT
(abstract data type) `LimitCounter`.
Introduces:
* Position dependent meaning of `const` when applied to pointers
* (Also: "step by step" approach with intermediate compilation)
### Variants (partial solutions)
* Step_03x: intermediate step to be turned into Step_04
* Step_03y: demonstrate use of two instances for CLI testing
* Step_03z: demonstrate everything is still C compatible
## Step_04
Achieved:
* Clean ADT as C-compatible solution
* demonstrated use of two separate `LimitCounter with TDD
### Main Stream -> Step 05
Goals:
* Turn pointer arguments into references
Introduces:
* Reference arguments
* `const` vs. non-`const` references
### Variants
* Step_04x: Demonstrate references are implemented as pointers
* Step_04y: Clean solution for Step_01z (no trickery)
## Step_05
(ADT `LimitCounter` WITHOUT access protection)
### Main Stream -> Step 06
Enforcing access protection by turning `struct LimitCounter`
into `class LimitCounter`.
Introduces:
* `private` and `public`
* Member functions
### Variants
* Step_05x: Introducing the `friend` mechanism
* Step_05y: special `getter` / `setter` overloading
## Step_06
(ADT `LimitCounter` WITH access protection)
### Main Stream -> Step_07
Guaranteed and flexible Initialization
Introduces:
* Constructors
* Constructor Overloading
### Variants
* Step_06x: Necessity of destructors
* Step_06y: Implementing copy operations
* Step_06z: Move vs. Copy / Move-only types
## Step_07
### Main Stream -> Step_08
Operator Overloading
### Variants
* Step_07x: Best Practices: assignment-combined operators)
* Step_07y: Incoming type conversions (non-`explicit` c'tors)
* Step_08y: Outgoing type conversions ("type-cast" operators)
## Step_08
### Main Stream -> Step_09
`ChainCounter` class using pointers and composition
Introduces:
* Reuse via composition
### Variants
* Step_09x: `ChainCounter` as derived class from `LimitCounter`
* Step_09y: Composition via private base class
* Step_09z: demonstrate limitations of static binding
## Step_09
### Main Stream -> Step_10
`ChainCounter` class using `LimitCounter` as base class
Introduces:
* Base and Derived Classes
* Dynamic Polymorphism
### Variants
* Step_09x: Applying the NVI idiom ("Non Virtual Interface")
## Step_10
### Main Stream -> Step_11
Adding an `ICounter`-Interface
Introduces:
* Abstract classes
* Pure virtual member functions
## Step_12
Chainable Counter with an Interface
Step 02 -> Step 03
Generelles Ziel: den "oberen Anschlag" des Zählers flexibler machen.
Führen Sie eine neue GLOBALE variable `limit` ein und verwenden Sie diese an allen Stellen, wo bisher ÌNT_MAX` verwendet wurde.
Step 03 -> Step 04
Fassen Sie die globalen Variablen `counter` und `limit` zu einer Struktor `LimitCounter` zusammen.
Legen Sie EINE globale Variable dieser Struktur an. Modifizieren Sie aber die Funktionen, die bisher auf `counter` und `limit` zugeriffen haben, s, dass Sie als Argument einen Zeiger auf `LimitCounter` oder `const LimitCounter` erwarten und übergeben Sie beim Aufruf die Adresse der globalen `LimitCounter` Variablen.
Step 04 -> Step 05
Verwenden Sie statt des Zeiger-Parameters eine Referenz.
Link zu Zip-File mit Step_00 bis Step_04
https://drive.google.com/file/d/1k8dcedMeP3xkG8oikCWG-nyeyR5vTn55/view?usp=sharing
# 1_Counter Step 0 (action items)
## Review the code and answer some questions:
* **Don't do a full review right now!**
* Allow yourself about the time specified with each step to
look over the code.
* Generally focus on parts you do NOT easily understand so
that YOU can ask questions later.
### `main.c` (5 Minutes)
* Before you read the comment at the start:
* Do you encounter any problems **at the syntax level** in
understanding the source code of this program?
* Do you understand what the **C Standard Library Functions**
used in that code are supposed to do?
* With reading the comment at the start:
* Are you able to **give a rough description** what the
program is supposed to do even before looking in `counter.h`
and `counter.c`?
### `counter.h` and `counter.c` (3 minutes)
* Identify which global variable is accessed by the functions
defined in that module.
* Does this module do what you would conclude if you had only
read the comment at its start?
### `Makefile` (1 minute)
* Can you identify the lines in which the the compiler is told
which version of the C language specification it should use?
You are not supposed to have or develop a deep understanding of
the build specifications in a `Makefile`. Still feel free to ask
questions if you are interested in that topic.
### General
* Can you name one or two differences between C89 and C99 that
are the reason why `main.c` is "C89" but counter.c is "C99"?
--------
main.c
/*
* ===========================================================================
* Random Risc Game Simulator (with "counter" implemented as separate module)
* ===========================================================================
* This program simulates the outcome of taking random risks, which may cause
* a loss or increase of your starting capital. The simulation runs until a
* everything is lost or a certain goal is reached (per default doubling the
* start capital). Via command line arguments these simulation parameters can
* be set:
* (1) a delimiter for the maximum capital to risk or gain in each step
* (2) the start capital as percentage of the goal that should be reached
* (3) variation of outcome (see below)
* The simulation is based on the random number generator of the C standard
* library. The generator is NOT seeded so that you get reproducible results
* on repeated runs with the same setting of the first two arguments. It is
* possible to get different but still reproducible) variants of the outcome
* for a given setting of the first two parameters by varying the third one,
* which determines whether the next risk taken will be a win or a loose.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "counter.h"
int main(int argc, char* argv[]) {
int const n = (argc > 1) ? atoi(argv[1]) : 5; /* risk delimiter */
double const m = (argc > 2) ? atof(argv[2]) : 50; /* start position */
int const b = (argc > 3) ? atoi(argv[3]) : 0; /* win/loose switch */
int runs = 0;
enum { UP = '+', DOWN = '-' } dir = UP;
counter = (int)(m/100 * INT_MAX);
do {
int r;
for (r = rand()/n; r > 0; --r) {
switch (dir) {
case UP:
count_up(); break;
case DOWN:
count_down(); break;
}
}
dir = (rand() & (1<<b)) ? UP : DOWN;
printf("%c|%c counter: %010d (runs=%d)\n",
(counter < INT_MAX/2) ? '-' : '+',
(char)dir, counter, ++runs);
} while (counter != 0 && counter != INT_MAX);
return 0;
}
--------
counter.h
/* Module Header
* ============================================================================
* Globally accessible non-overflow / non-underflow counter
* ============================================================================
* This file is to be included if that `counter` is used by some other module.
* For more information see file `counter.c`.
*/
#ifndef COUNTER_H_
#define COUNTER_H_
int counter;
void count_up();
void count_down();
void reset();
#endif /* include guard */
---------
counter.c
/* Module Implementation
* ============================================================================
* Globally accessible non-overflow / non-underflow counter
* ============================================================================
* The variable `counter` is meant to be accessible from other modules if this
* file is compiled to an object module. To MODIFY it only the three functions
* provided here should be use. They make sure that once the lowest or highest
* limit is reached no wrap-around will occur.
*/
#include "counter.h"
#include <limits.h>
int counter = 0;
void count_up() {
if (counter == INT_MAX) {
return;
}
++counter;
}
void count_down() {
if (counter == 0) {
return;
}
--counter;
}
void reset() {
counter = 0;
}
---------
Makefile
# !! Be sure indented lines below start with a TAB character (= ASCII \x09) !!
# (such are syntactically significant for `make` and not equivalent to spaces)
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# un-comment the following line if your IDE by default builds a target `all`
#all: info
# ^-- you may also want to change `info` to the prefered target to build
info:
@echo 'use `make run`, `make tdd`, or `make cli` to compile/run a program'
@echo '(furthermore `make clean` purges compiled objects and executables)'
CC=gcc -std=c89
.PHONY: all info run cli tdd clean
run: subdirs programs/run-main
@programs/run-main
tdd:
@echo 'test driven development not supported'
cli:
@echo 'no interactive cli-testing provided'
clean:
rm -rf objects programs
@rm -f a.out core
subdirs:
@test -d programs || mkdir programs
@test -d objects || mkdir objects
objects/run-main.o: main.c counter.h
$(CC) -c main.c -o $@
objects/counter.o: counter.h
$(CC) -c counter.c -o $@
programs/run-main: objects/run-main.o objects/counter.o
$(CC) objects/run-main.o objects/counter.o -o $@
# EOF