Skip to content
Snippets Groups Projects
Commit 009b96c5 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Skript bis einschließlich Kapitel 6: Objektorientierte Programmierung

parent 57097978
Branches
No related tags found
No related merge requests found
No preview for this file type
...@@ -4329,7 +4329,7 @@ ...@@ -4329,7 +4329,7 @@
Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\ Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\
Suchbegriff: setMotorDir Suchbegriff: setMotorDir
\goodbreak \goodbreak
\begin{verbatim} \begin{lstlisting}
void setMotorDir(uint8_t left_dir, uint8_t right_dir) void setMotorDir(uint8_t left_dir, uint8_t right_dir)
{ {
mleft_dir = left_dir; mleft_dir = left_dir;
...@@ -4344,7 +4344,8 @@ ...@@ -4344,7 +4344,8 @@
PORTC |= DIR_R; PORTC |= DIR_R;
else else
PORTC &= ~DIR_R; PORTC &= ~DIR_R;
}\end{verbatim} }
\end{lstlisting}
Die Variable \lstinline|PORTC| ist ein Output-Port. Die Variable \lstinline|PORTC| ist ein Output-Port.
Durch Manipulation einzelner Bits in dieser Variablen Durch Manipulation einzelner Bits in dieser Variablen
...@@ -4381,13 +4382,14 @@ ...@@ -4381,13 +4382,14 @@
Beispiel für die Verwendung eines Interrupts: Roboter-Steuerung\\ Beispiel für die Verwendung eines Interrupts: Roboter-Steuerung\\
Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\ Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\
Suchbegriff: ISR Suchbegriff: ISR
\begin{verbatim} \begin{lstlisting}
ISR (INT0_vect) ISR (INT0_vect)
{ {
mleft_dist++; mleft_dist++;
mleft_counter++; mleft_counter++;
/* ... */ /* ... */
}\end{verbatim} }
\end{lstlisting}
\begin{itemize} \begin{itemize}
\item \item
Durch das Schlüsselwort \lstinline|ISR| anstelle von z.\,B.\ \lstinline|void| Durch das Schlüsselwort \lstinline|ISR| anstelle von z.\,B.\ \lstinline|void|
...@@ -4482,10 +4484,9 @@ ...@@ -4482,10 +4484,9 @@
\subsection{volatile-Variable} \subsection{volatile-Variable}
Im C-Quelltext fällt auf, daß die Zähler-Variablen \lstinline|mleft_dist| und \lstinline|mleft_counter| Im C-Quelltext fällt auf, daß die Zähler-Variablen \lstinline|mleft_dist| und \lstinline|mleft_counter|\\
als \lstinline|volatile|\break\lstinline|uint16_t mleft_counter| bzw.\ \lstinline|volatile uint16_t mleft_dist| deklariert als \lstinline|volatile uint16_t mleft_counter| bzw.\ \lstinline|volatile uint16_t mleft_dist| deklariert sind\\
sind anstatt einfach nur als anstatt einfach nur als \lstinline|uint16_t mleft_counter| und \lstinline|uint16_t mleft_dist|.
\lstinline|uint16_t mleft_counter| und \lstinline|uint16_t mleft_dist|.
Das Schlüsselwort \lstinline|volatile| teilt dem C-Compiler mit, Das Schlüsselwort \lstinline|volatile| teilt dem C-Compiler mit,
daß eine Variable immer im Speicher (RAM) aufbewahrt werden muß daß eine Variable immer im Speicher (RAM) aufbewahrt werden muß
...@@ -5430,10 +5431,153 @@ ...@@ -5430,10 +5431,153 @@
\subsection{Virtuelle Methoden} \subsection{Virtuelle Methoden}
\underconstruction In großen Programmen wird die Anzahl der verwendeten Objekt-Datentypen
schnell sehr groß. Eine Methode, die per \lstinline{if} unterscheiden muß,
welche Art von Objekt sie gerade bearbeitet,
enthält dann lange \lstinline{if}-Ketten
und wird dadurch sehr unübersichtlich.
\begin{lstlisting}
void print_object (t_object *this)
{
if (this->base.type == T_INTEGER)
printf ("Integer: %d\n", this->integer.content);
else if (this->base.type == T_STRING)
printf ("String: \"%s\"\n", this->string.content);
}
\end{lstlisting}
Es wäre vorteilhaft, wenn alle Methoden,
die sich auf einen bestimmten Objekttyp beziehen,
auch nebeneinander im Quelltext stehen könnten,
anstatt sich über viele Funktionen zu verteilen.
\begin{lstlisting}
void print_integer (t_object *this)
{
printf ("Integer: %d\n", this->integer.content);
}
void print_string (t_object *this)
{
printf ("String: \"%s\"\n", this->string.content);
}
\end{lstlisting}
Um dies zu realisieren, verwendet man \emph{Zeiger auf Funktionen}:
\begin{lstlisting}
typedef struct
{
void (*print) (union t_object *this);
} t_base;
typedef struct
{
void (*print) (union t_object *this);
int content;
} t_integer;
typedef struct
{
void (*print) (union t_object *this);
char *content;
} t_string;
\end{lstlisting}
Um einen Zeiger auf eine Funktion zu deklarieren,
deklariert man eine "`normale"' Funktion,
deren "`Name"' die Gestalt \lstinline{(*print)} hat --
mit dem vorangestellten Stern und den umschließenden Klammern.
(Merkregel: Das, worauf \lstinline{print} zeigt -- also \lstinline{*print} --,
ist eine Funktion.)
Der Aufruf einer derartigen Funktion erfolgt
über den im Objekt gespeicherten Zeiger:
\begin{lstlisting}
for (int i = 0; object[i]; i++)
object[i]->print (object[i]);
\end{lstlisting}
Eine derartige Funktion, die für verschiedene Objekttypen existiert
und bei deren Aufruf automatisch "`die passende"' Funktion ausgewählt wird,
heißt \newterm{virtuelle Methode}.
\breath
Jeder Methode wird ein Zeiger \lstinline{t_object *this} auf das Objekt
als Parameter mitgegeben.
Bei der Deklaration der virtuellen Methode innerhalb des Objekt-Typs
wird daher der Union-Typ \lstinline{t_object} bereits benötigt.
Dieser kann jedoch erst später deklariert werden,
wenn die darin enthaltenen Objekt-Typen bekannt sind.
Um dieses Problem zu lösen, muß die \lstinline{union t_object}
"`doppelt"' deklariert werden:
\begin{lstlisting}
typedef union t_object
{
t_base base;
t_integer integer;
t_string string;
} t_object;
\end{lstlisting}
Dadurch daß \lstinline{t_object} auch oben,
hinter dem Schlüsselwort \lstinline{union} steht,
ist neben dem Datentyp \lstinline{t_object}
auch ein Datentype \lstinline{union t_object}
(in einem separaten Namensraum) bekannt.
Derartig deklarierte Typen kann man \newterm{vorwärts-deklarieren\/}:
Wenn man eine Zeile
\begin{lstlisting}
union t_object;
\end{lstlisting}
den anderen Deklarationen voranstellt,
wissen diese, daß es später eine \lstinline{union t_object} geben wird.
Zeiger auf diese -- noch unbekannte -- \lstinline{union}
dürfen dann bereits in Deklarationen -- hier: Funktionsparameter --
verwendet werden.
\breath
Das Beispiel-Programm \gitfile{20170109}{objects-12.c} illustriert,
wie man virtuelle Methoden in C realisieren kann.
In größeren Projekten ist es nicht effizient,
in jeder einzelnen Objektinstanz (= Variable des Objekttyps)
sämtliche Zeiger auf sämtliche virtuellen Methoden zu speichern.
Stattdessen speichert man in der Objektinstanz
lediglich einen Zeiger auf eine Tabelle von Zeigern auf die virtuellen Methoden,
die sog.\ \newterm{virtuelle Methodentabelle} --
siehe das Beispiel-Programm \gitfile{20170109}{objects-13.c}.
\subsection{Einführung in C++} \subsection{Einführung in C++}
Objektorientierte Programmierung in C ist sehr mühselig und fehleranfällig:
Objekt-Datentypen müssen manuell so abgeglichen werden,
daß sie in ihren ersten Datenfeldern übereinstimmen,
Konstruktoren müssen manuell erstellt werden, usw.
Um diese Probleme zu beheben, wurden neue Computersprachen entwickelt,
die objektorientierte Programmierung durch neue Sprachelemente unterstützen.
Die objektorientierte Weiterentwicklung von C ist C++.
Andere bekannte objektorientierte Sprachen sind Java, C\#, Python, JavaScript,
PHP, verschiedene Pascal-Dialekte und viele weitere.
Das Beispiel-Programm \gitfile{20170109}{objects-14.cpp}
ist eine direkte Übersetzung von \gitfile{20170109}{objects-12.c} nach C++.
In C++ kümmert sich der Compiler um die Vererbung zwischen den Objekt-Datentypen,
um die Verwaltung der Zeiger auf virtuelle Methoden,
um korrekte Konstruktoren und um vieles mehr.
Auch die Übergabe des Objekt-Zeigers \lstinline{this} an Methoden
erfolgt in C++ automatisch: Aus \lstinline{object[i]->base.print (object[i]);}
wird \lstinline{object[i]->print ();}.
Der Quelltext wird dadurch kürzer und weniger fehleranfällig.
\section{Datenstrukturen} \section{Datenstrukturen}
\underconstruction \underconstruction
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment