1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
\documentclass[12pt,a4paper,titlepage,oneside]{article}
\usepackage[utf8]{inputenc}
\usepackage{oop_prot}
\usepackage{url}
\usepackage{pdfpages}
\usepackage{booktabs}
\title{Beispiel 1}
\author{Manuel Mausz, \matrnr 0728348\\
{\small manuel-tu@mausz.at}
}
\begin{document}
% create titlepage
\maketitle
\tableofcontents
\newpage
%------------------------------------------------------------------
%------------------------------------------------------------------
\section{Aufgabenstellung - Beispiel 1}
\includegraphics[width=\textwidth,page=1]{../angabe.pdf}
\includegraphics[width=\textwidth,page=2]{../angabe.pdf}
%------------------------------------------------------------------
%------------------------------------------------------------------
\section{Beispiel 1}
\subsection{Design}\label{Design}
Abbildung~\ref{fig:classdiagram1} zeigt das Klassendiagramm der Aufgabe.
Die Klasse CScriptParser übernimmt das Parsen der per Commandlineparameter
übergebenen Scriptdatei als String, wobei dieser bereits im Konstruktor
übergeben werden muss. Zum Anstoßen des Parsen dient die Funktion parse().
Der (simple) Parser arbeitet Zeilenbasiert und erwartet pro Zeile einen
Funktionsaufruf im Syntax: funktionsname(param1, ... paramX). Schachteln von
Funktionen ist nicht erlaubt. Der erste Befehl eines Blocks muss der Befehl
``read'' sein, der Befehl ``write'' beendet einen Block. Alle Funktionsparameter
werden zusammen in einer Liste gespeichert und den entsprechenden Funktionen
übergeben. Whitespaces und Anführungszeichen werden bereits vorab gelöscht.
Tritt ein Fehler während des Parsens auf, werden Instanzen der Klasse
\mbox{CSriptError::ParserError} als Exception geworfen. Über die Methode
\mbox{getLine()} der Exception kann die aktuelle Zeile der Scriptdatei, die den
Fehler erzeugt hat, ausgelesen werden.\\
Da der Scriptbefehl ``read'' und ``write'' einen Dateitypparameter enthält,
ist es potentiell möglich verschiedene Dateitypen zu öffnen und zu bearbeiten.
Um dies aus der Sicht des Parsers generisch durchzuführen, müssen alle Klassen,
die Dateioperationen durchführen können, von der Abstrakten Klasse \mbox{CFile}
abgeleitet sein und somit mindestens dessen virtuelle Methoden implementieren.
Alle Implementation müssen weiters im Konstruktor die unterstützten Dateitypen
in die Membervariable m\_types hinzufügen, damit der Parser die jeweils
zuständige Implementation verwenden kann.
Die Methode \mbox{callFunc(...)} dient zum Aufruf von dateitypspezifische
Scriptfunktionen. Hierzu übergibt der Parser automatisch alle unbekannten
Funktionen und dessen Parameter innerhalb eines Block (abgesehen von ``read''
und ``write'') der jeweils zuständigen Instanz.
Zur Fehlerbehandlung sollen Implementationen von CFile Instanzen der
Klasse \mbox{CFile::FileError} als Exception werfen. Diese werden vom Parser
gefangen und in Instanzen der eigenen Exception des Parsers
\mbox{CSriptError::ParserError} übersetzt.\\
Die Klasse \mbox{CBitmap} implementiert die Abstrakte Klasse \mbox{CFile} und
kann Dateien des Types ``BMP'' (Windows Bitmap) bearbeiten. Beim Lesen der
Datei werden rudimentäre Checks des Dateiheaders durchgeführt. Der Speicher der
Pixel, wird wie gewünscht dynamisch alloziert. Um aber die verschiedenen
möglichen Farbtiefen von Windows Bitmap zu unterstützen, werden die
Schreiboperationen auf die Pixeldaten an eine Instanz der je nach Farbtiefe
zuständigen Implementation der Abstrakten Klasse \mbox{CPixelFormat} delegiert.
Diese Instanz wird während der Analyse des Dateiheaders ebenfalls dynamisch
allokiert.\\
Damit Implementationen der abstrakten Klasse \mbox{CPixelFormat} direkt auf die
Daten des Windows Bitmap zugreifen können, wird im Konstruktor ein Pointer auf
die Instanz von \mbox{CBitmap} übergeben. Über die Public Getter-Methoden von
\mbox{CBitmap} erfolgt der direkt Zugriff. Fehlerbehandlung erfolgt
Exceptions der Klasse \mbox{CPixelFormat::PixelFormatError}.
%==================================================================
\begin{figure}[htb]
\begin{center}
\epsfxsize=0.9\textwidth\epsfbox{ClassDiagram1.png}
\end{center}
\caption{Klassendiagramm 1}
\label{fig:classdiagram1}
\end{figure}
%==================================================================
\subsection{Verwaltung der Ressourcen}
Alle Klassen, die im Laufe ihrer Existenz Ressourcen dynamische
allozieren, initialisieren die jeweiligen Membervariablen im Konstruktor auf
NULL und geben diese, sofern tatsächlich alloziert, im spätestens Destruktor
wieder frei.\\
Alle Dateien, die geöffnet werden, werden nach dem Abfangen der Exception auch
wieder geschlossen, sofern alle möglichen, auftretenden Exceptions
(\mbox{std::bad\_alloc} ausgenommen) auch vorab übersetzt wurden.
\subsection{Fehlerbehandlung}
Alle Implementationen der abstrakten Klasse \mbox{CPixelFormat} werfen
Exceptions der Klasse \mbox{CPixelFormat::PixelFormatError}. Diese werden von
\mbox{CBitmap} gefangen und in Exceptions der Klasse \mbox{CFile::FileError}
übersetzt, welche wiederum von der Klasse \mbox{CScriptParser} gefangen und in
Exceptions der Klasse \mbox{CScriptParser::ParserError} übersetzt werden.\\
Diese Exceptions sowie Exceptions des Typs \mbox{std::exception} werden
schlussendlich vom Hauptprogramm gefangen und geben eine entsprechende
Fehlermeldung an den Benutzer auf stderr aus.
\subsection{Implementierung}
Siehe Punkt~\ref{Design} und Abbildung~\ref{fig:classdiagram1} sowie
Punkt~\ref{Listings}.
Alle Exceptions wurden von \mbox{std::invalid\_argument} abgeleitet und der
Konstruktor gemäß den üblichen Konventionen implementiert:
%==================================================================
\begin{lstlisting}{}
ParserError(const std::string& what)
: std::invalid_argument(what)
{}
\end{lstlisting}
%==================================================================
%------------------------------------------------------------------
%------------------------------------------------------------------
\section{Projektverlauf}
\subsection{Probleme und Fallstricke}
In der Hoffnung das in der nächsten Aufgabe weitere Funktionen, Dateitypen
und/oder Farbtiefen des Windows Bitmaps-Formats verlangt werden, wurden
diese sehr generisch implementiert.\\
Ursprünglich wollte ich die jeweilig unterstützen Scriptfunktionen mittels
\mbox{std::map<std::string, (void *)()>} an den Scriptparser zurückgeben,
sodass dieser direkt die jeweilige Methode (per Pointer) aufrufen kann. Dies
funktioniert jedoch logischerweise nur bei statischen Methoden. Daher die
einfacher Methode über die callFunc-Methoden, die die Parameter an die
jeweiligen internen Methoden weiterdelegieren.
Da sich \mbox{CBitmap} und \mbox{CPixelFormat} gegenseitig referenzieren,
müssen die jeweiligen Klassen im Headerfile der anderen Klasse vorab deklariert
werden. Andernfalls kann der Compiler die Klasse aufgrund der rekursiven
Inklusion nicht finden.
\subsection{Arbeitsaufwand}
\begin{tabular}{ll}
\toprule
Entwicklungsschritt / Meilenstein & Arbeitsaufwand in Stunden\\
\midrule
Erstes Design & 15 Minuten\\
\hline
Implementierung (und leichte Anpassung des Designs) & 1 Tag\\
\hline
Dokumentation (Doxygen) und Überprüfung alle\\
Anforderungen gemäß der Programmierrichtlinien & 2 Tage\\
\hline
Erstellung des Protokolls & 1 Tag\\
\bottomrule
\end{tabular}
%------------------------------------------------------------------
%------------------------------------------------------------------
\section{Listings}\label{Listings}
\subsection{imgsynth.cpp}
\lstinputlisting{../imgsynth/imgsynth.cpp}
\newpage
\subsection{cscriptparser.h}
\lstinputlisting{../imgsynth/cscriptparser.h}
\newpage
\subsection{cscriptparser.cpp}
\lstinputlisting{../imgsynth/cscriptparser.cpp}
\newpage
\subsection{cfile.h}
\lstinputlisting{../imgsynth/cfile.h}
\newpage
\subsection{cbitmap.h}
\lstinputlisting{../imgsynth/cbitmap.h}
\newpage
\subsection{cbitmap.cpp}
\lstinputlisting{../imgsynth/cbitmap.cpp}
\newpage
\subsection{cpixelformat.h}
\lstinputlisting{../imgsynth/cpixelformat.h}
\newpage
\subsection{cpixelformat\_24.h}
\lstinputlisting{../imgsynth/cpixelformat_24.h}
\newpage
\subsection{cpixelformat\_24.cpp}
\lstinputlisting{../imgsynth/cpixelformat_24.cpp}
\end{document}
|