Hinweise:
- Eigenes Print für die Klassen verwenden
- Einrücken und Stil vereinheitlichen ( am Besten Alt+Umschalt+F )
- Helper Funktionen als Private Methoden einbauen
- Variablen klarer und mit sprechenden Namen benennen
- Die Menüstruktur „Interaktiv und Zufall“ als Boolean implementieren
- Manager Klasse für die Helper Funktionen und Sammlung bauen
- Mit Enum die Auswahl für das Menü begrenzen
Aufgabe 1:
a) Bearbeiten Sie die Klausur aus dem ersten Semester. Versuchen Sie, eine möglichst hochwertige Lösung anzufertigen, achten Sie besonders auf Qualität. Lösung:
/*
* File: bib.cpp
* Author: NROGMANN
*
* Created on 22. März 2012, 09:17
*/
// Präprozessor-Direktiven
#include "bib.h"
#include <iostream>
// Using-Deklarationen
using std::string;
using std::cout;
// Prototypen
extern void error(string);
// Reader
Reader::Reader()
: name(), num_books(0) {
}
Reader::Reader(string s, int n)
: name(s), num_books(n) {
}
string Reader::get_name() const {
return name;
}
void Reader::set_name(string s) {
name = s;
}
int Reader::get_nbooks() const {
return num_books;
}
void Reader::inc_nbooks() {
num_books++;
}
// Book
Book::Book()
: title(), author(), on_shelf(true) {
}
Book::Book(string t, string a)
: title(t), author(a), on_shelf(true) {
}
string Book::get_title() const {
return title;
}
string Book::get_author() const {
return author;
}
bool Book::get_onshelf() const {
return on_shelf;
}
void Book::set_onshelf(bool b) {
on_shelf = b;
}
// Loan
Loan::Loan()
: sLender(), pBorrowed(0) {
}
Loan::Loan(string s, Book* b)
: sLender(s), pBorrowed(b) {
}
string Loan::get_lender() {
return sLender;
}
Book* Loan::get_borrowed() {
return pBorrowed;
}
void Loan::print() {
cout << sLender << "\tleiht\t"
<< pBorrowed->get_title()
<< "("
<< pBorrowed->get_author()
<< ")"
<< std::endl;
}
/*
* File: bib.h
* Author: NROGMANN
*
* Created on 22. März 2012, 09:17
*/
#ifndef BIB_H
#define BIB_H
#include <string>
using std::string;
class Reader {
private:
string name;
int num_books;
public:
Reader();
Reader(string, int);
string get_name() const;
void set_name(string);
int get_nbooks() const;
void inc_nbooks();
};
class Book {
private:
string title;
string author;
bool on_shelf;
public:
Book();
Book(string, string);
string get_title() const;
string get_author() const;
bool get_onshelf() const;
void set_onshelf(bool);
};
class Loan {
private:
string sLender;
Book * pBorrowed;
public:
Loan();
Loan(string, Book*);
string get_lender();
Book* get_borrowed();
void print();
};
#endif /* BIB_H */
/*
* File: error_catch.h
* Author: NROGMANN
*
* Created on 22. März 2012, 09:07
*/
#ifndef ERROR_CATCH_H
#define ERROR_CATCH_H
#include <stdexcept>
#include <string>
#include <iostream>
using std::runtime_error;
using std::out_of_range;
using std::cerr;
using std::string;
void error(string s) {
throw runtime_error(s);
}
/*
catch( runtime_error &e ) {
cerr << "Laufzeitfehler: " << e.what() << '\n';
return 1;
}
catch( ... ) {
cerr << "Unbekannter Ausnahmefehler" << '\n';
return 2;
}
*/
#endif /* ERROR_CATCH_H */
/*
* File: main.cpp
* Author: NROGMANN
*
* Created on 22. März 2012, 09:07
*/
// Präprozessor-Direktiven
#include <iostream>
#include <iomanip>
#include <vector>
#include "error_catch.h"
#include "bib.h"
// Using-Deklarationen
using std::vector;
using std::cout;
using std::cin;
using std::endl;
// Prototypen
void populate_books(vector<Book>&vBooks, string title, string author);
void print_books(vector<Book>&vBooks);
void populate_readers(vector<Reader>&vReaders, string name, int num);
void print_readers(vector<Reader>&vReaders);
void add_reader(vector<Reader>&vReaders);
void populate_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders, string reader, string title, string author);
void print_loans(vector<Loan>&vLoans);
void add_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders);
Reader* identify_reader(vector<Reader>&vReaders, string name);
Book* identify_book(vector<Book>&vBooks, string title, string author);
int main() {
try {
// Objekte anlegen
vector<Book>vBooks;
vector<Reader>vReaders;
vector<Loan>vLoans;
// Objekte füllen
populate_books(vBooks, "Suppen", "Schlawiner");
populate_books(vBooks, "Desserts", "Schlawiner");
populate_books(vBooks, "C++", "Stroustrup");
populate_books(vBooks, "C++", "Petersen");
populate_books(vBooks, "Bergtouren", "Rittersdorf");
populate_books(vBooks, "XML", "Manfreti");
populate_books(vBooks, "Feuersteine", "Hibbler");
populate_books(vBooks, "Dinosaurier", "Gould");
populate_books(vBooks, "Pandas", "Gould");
populate_books(vBooks, "Scherz", "Kundera");
populate_readers(vReaders, "Barney", 0);
populate_readers(vReaders, "Betty", 0);
populate_readers(vReaders, "Fred", 0);
populate_readers(vReaders, "Wilma", 0);
// Ausgabe
print_books(vBooks);
print_readers(vReaders);
// Weitere Leser hinzufügen
add_reader(vReaders);
// Ausleihe hinzufügen
populate_loans(vLoans, vBooks, vReaders, "Betty", "C++", "Stroustrup");
populate_loans(vLoans, vBooks, vReaders, "Betty", "XML", "Manfreti");
populate_loans(vLoans, vBooks, vReaders, "Fred", "C++", "Petersen");
populate_loans(vLoans, vBooks, vReaders, "Fred", "Feuersteine", "Hibbler");
populate_loans(vLoans, vBooks, vReaders, "Wilma", "Bergtouren", "Rittersdorf");
print_loans(vLoans);
add_loans(vLoans, vBooks, vReaders);
} catch (out_of_range &e) {
cerr << "Out of Range: " << e.what() << '\n';
return -1;
} catch (runtime_error &e) {
cerr << "Laufzeitfehler: " << e.what() << '\n';
return -2;
} catch (...) {
cerr << "Unbekannter Ausnahmefehler" << '\n';
return -3;
}
return 0;
}
void populate_books(vector<Book>&vBooks, string title, string author) {
vBooks.push_back(Book(title, author));
}// populate_books
void print_books(vector<Book>&vBooks) {
cout << "Buchliste:\n";
cout << std::setw(15) << std::left << "Titel\t\tAutor\t\tBestand" << endl;
for (int i = 0; i < vBooks.size(); i++) {
cout << std::setw(15) << std::left << vBooks.at(i).get_title() << "\t"
<< std::setw(15) << std::left << vBooks.at(i).get_author() << "\t"
<< vBooks.at(i).get_onshelf() << endl;
}
cout << endl;
}// print_books
void populate_readers(vector<Reader>&vReaders, string name, int num) {
vReaders.push_back(Reader(name, num));
}// populate_readers
void print_readers(vector<Reader>&vReaders) {
cout << "Leserliste:\n";
cout << std::setw(15) << std::left << "Name\t\tAusgeliehen" << endl;
for (int i = 0; i < vReaders.size(); i++) {
cout << std::setw(15) << std::left << vReaders.at(i).get_name() << "\t"
<< vReaders.at(i).get_nbooks() << endl;
}
cout << endl;
}// print_readers
void add_reader(vector<Reader>&vReaders) {
bool bFinished = false;
while (!bFinished) {
bool bDouble = false;
string strTemp = "";
cout << "Weitere Leser hinzufügen (beenden mit 'q'): ";
cin >> strTemp;
// Prüfe, ob Eingabe gültig
if (!cin)
error("Fehlerhafte Eingabe");
if (cin.peek() == EOF)
error("End of File..");
// Schleifenabbruch
if (strTemp == "q") {
bFinished = true;
break;
}
// Check, ob neuer Leser schon in Leserliste
for (int i = 0; i < vReaders.size(); i++) {
if (strTemp == vReaders.at(i).get_name()) {
bDouble = true;
break;
}
} // for
// Wenn Name nicht vorhanden
if (!bDouble) {
// Leser hinzufügen
populate_readers(vReaders, strTemp, 0);
cout << "Leser " << strTemp << " hinzugefügt\n";
print_readers(vReaders);
} else {
cout << "Fehler: Leser schon vorhanden!\n";
}
}// while
cout << endl;
}// add_reader
void populate_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders, string name, string title, string author) {
Reader* pReader = identify_reader(vReaders, name);
Book* pBook = identify_book(vBooks, title, author);
if (pReader != 0 && pBook != 0) {
vLoans.push_back(Loan(name, pBook));
pReader->inc_nbooks();
pBook->set_onshelf(false);
} else {
error("Buch oder Leser nicht vorhanden!");
}
}// populate_loans
void print_loans(vector<Loan>&vLoans) {
cout << "Ausleihe:\n";
for (int i = 0; i < vLoans.size(); i++)
vLoans.at(i).print();
}// print_loans
void add_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders) {
bool bFinished = false;
while (!bFinished) {
string strReader = "";
string strBook = "";
string strAuthor = "";
cout << "\nWeitere Ausleihen hinzufügen (beenden mit 'q')\n"
<< "('Leser' 'Buch' 'Author'): ";
cin >> strReader;
if (!cin)
error("Fehlerhafte Eingabe");
if (cin.peek() == EOF)
error("End of File..");
if (strReader == "q") {
bFinished = true;
break;
}
cin >> strBook >> strAuthor;
if (!cin)
error("Fehlerhafte Eingabe");
if (cin.peek() == EOF)
error("End of File..");
// Prüfe, ob Buch schon ausgeliehen
Book* pBook = identify_book(vBooks, strBook, strAuthor);
if (pBook == 0) {
error("Buch nicht vorhanden");
} else {
if (pBook->get_onshelf() == false) {
cout << "Buch schon ausgeliehen\n";
continue;
}
}
// Prüfe, ob Leser "registriert"
Reader* pReader = identify_reader(vReaders, strReader);
if (pReader == 0) {
cout << "Fehler: Benutzer nicht registriert\n";
} else {
populate_loans(vLoans, vBooks, vReaders, strReader, strBook, strAuthor);
cout << endl;
print_readers(vReaders);
print_books(vBooks);
print_loans(vLoans);
cout << "\nBuch erfolgreich ausgeliehen\n";
}
}// while
}// add_loans
Reader* identify_reader(vector<Reader>&vReaders, string name) {
// Leserobjekt identifizieren
for (int j = 0; j < vReaders.size(); j++) {
if (vReaders.at(j).get_name() == name) {
return &vReaders.at(j);
}
}
return 0;
}// identify_reader
Book* identify_book(vector<Book>&vBooks, string title, string author) {
// Buch eindeutig identifizieren
for (int i = 0; i < vBooks.size(); i++) {
if (vBooks.at(i).get_title() == title) {
if (vBooks.at(i).get_author() == author) {
return &vBooks.at(i);
}
}
}
return 0;
}// identify_book
b) Formulieren Sie ein eigenes Beispiel für eine entsprechende Aufgabenstellung, die zukünftig als Klausur dienen könnte.
Aufgabe 2
a) Entwerfen und implementieren Sie eine Klasse namens NPV (net present value) für die Berechnung des Kapitalwerts C0 einer Zahlungsreihe, wobei das Endergebnis der Berechnung unter Berücksichtigung der 4/5-Rundung auf Hundertstel („zwei Stellen nach dem Komma“) genau sein soll. Sehen Sie für die Zahlungsreihe eine vector<long int> Membervariable namens inv (investment) in Hundertstel der Währung vor (lassen Sie die Denomination der Währung unbestimmt). Sehen Sie für den Kalkulationszinssatz eine double Membervariable namens irate (interest rate) vor, die auf vier Stellen nach dem Komma genau ist, also z.B. 0.0412 bei 4,12% pro Jahr. Gehen Sie von einem einzigen Zinssatz für die ganze Zahlungsreihe aus. Der t-te Wert in inv, d.h. also inv.at(t), steht damit für die saldierten monetären Zuflüsse (positiver Wert) bzw. Abflüsse (negativer Wert) im t-ten Jahr. Zur Abzinsung des t-ten Werts auf die Gegenwart dividieren Sie ihn durch (1 + irate )t . Der Kapitalwert C0 ist die Summe aller derart abgezinsten Werte aus inv.
Sehen Sie auch Konstruktoren vor, die zufällige Zahlungsreihen und Zinssätze erzeugen, um Ihnen beim Testen zu helfen.
/*
* File: error.h
* Author: maximilian.krieg
*
* Created on 26. März 2012, 13:53
*/
#ifndef ERROR_H
#define ERROR_H
#include <iostream>
#include <stdexcept>
using std::string;
using std::runtime_error;
inline void error(string s) {
throw runtime_error(s);
}
inline void error(string s1, string s2) {
error(s1 + s2);
}
#endif /* ERROR_H */
#ifndef NPV_H
#define NPV_H
#include <math.h>
#include <vector>
#include "error.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
//Defitionen: Klassen
class npv;
//Definitionen: Support - Funktionen -
double nachkommastelle(double, int);
double interestrate(double);
void ausgabe(const vector<npv>&, int);
void anlegen(vector<npv>&, int);
// Net-Present-Value-Klasse (Berechnung von Kapitalwert einer Zahlungsreihe) -
class npv {
public:
// Konstruktoren
npv(); // Standardkonstruktor
npv(vector<long int>, double); // Definierte Zahlungsreihe mit fester Rate
npv(int);
// Methoden zur Interest Rate
double set_irate(double); // interestrate setzen
double get_irate() const; // interestrate auslesen
// Methoden zum Investments
void set_inv(int, long int); // investment setzen
long int get_inv(int) const; // investment auslesen
int get_inv_years() const;
// Berechnungs-Methoden
double get_kapitalwert() const;
double get_abzinsung(int) const;
private:
vector<long int> inv;
double irate;
};
#endif /* NPV_H */
#include "npv.h"
#include <vector>
using namespace std;
// Standardkonstruktor
npv::npv() :
inv(0), irate(0) {
}
// Konstruktor für vorgebene Werte mit fester Rate
npv::npv(vector<long int> inv_value, double irate_value) :
inv(inv_value), irate(interestrate(irate_value)) {
}
// Konstruktor für Zufallsgenerierte Einträge
npv::npv(int iyears) :
inv(0), irate(0) {
srand(time(NULL));
vector<long int> inv_value(iyears);
irate = interestrate(rand() % 100 + 1);
inv_value.at(0) = (-1) * rand() % 100000 + 1;
for (int i = 1; i < iyears; i++) {
inv_value.at(i) = rand() % 10000 - rand() % 10000;
}
inv = inv_value;
}
// Anzahl der Einträge einer Zahlungsreihe auslesen
int npv::get_inv_years()const {
return inv.size();
}
// Investment im Jahr t auslesen
long int npv::get_inv(int t) const {
return inv.at(t);
}
// Investmentrate auslesen
double npv::get_irate() const {
return irate * 100;
}
// Veränderung der Zahlungsreihe
void npv::set_inv(int t, long int ivalue) {
inv.at(t) = ivalue;
}
// Kapitalwert berechnen
double npv::get_kapitalwert() const {
long int kapitalwert = inv.at(0);
for (int i = 1; i < inv.size(); i++) {
kapitalwert = kapitalwert + get_abzinsung(i);
}
return nachkommastelle(kapitalwert, 2) / 100;
}
// Abzinsung für das Jahr t
double npv::get_abzinsung(int iyear) const {
double dresult = 0;
double ddivision = 1;
long int ivalue = inv.at(iyear);
for (int i = 0; i < iyear; i++) {
ddivision = ddivision * (1 + irate);
}
if (ddivision != 0) {
dresult = ivalue / ddivision;
} else {
error("Interest Rate bei diesem Objekt erzeugt Division durch 0");
}
return dresult;
}
// Nachkommastelle mit Genauigkeit t berechnen
double nachkommastelle(double dwert, int istellen) {
if (istellen > 0) {
int imult = 1;
for (int i = 0; i < istellen; i++) {
imult = imult * 10;
}
dwert = dwert*imult;
dwert = dwert + 0, 5;
dwert = floor(dwert);
dwert = dwert / imult;
return dwert;
} else {
error("Ungültige Eingabe für die Anzahl der Nachkommastellen");
}
}
// irate umrechnen ( Aufruf aus Konstruktor )
double interestrate(double irate_new) {
irate_new = irate_new / 100;
irate_new = nachkommastelle(irate_new, 4);
return irate_new;
}
// Ausgabe einer Zahlungsreihe
void ausgabe(const vector<npv>& vnpv, int iposition) {
iposition = iposition - 1;
if (iposition >= 0 && iposition < vnpv.size()) {
cout << "\t" << "Kapitalanlage =\t " << vnpv[iposition].get_inv(0) << endl;
for (int i = 1; i < vnpv[iposition].get_inv_years(); i++) {
cout << "\t" << i << ". Jahr =\t " << vnpv[iposition].get_inv(i) << endl;
}
cout << "\tInterestrate = " << vnpv[iposition].get_irate() << "%" << endl;
cout << "\tKapitalwert = " << vnpv[iposition].get_kapitalwert() << endl;
} else {
error("Ungültige Eingabe bei der Auswahl des NPV.");
}
}
// Anlage einer Zahlungsreihe
void anlegen(vector<npv>& vnpv, int ianlegen) {
int iyears = 0;
int ianschaffung = 0;
int isaldo = 0;
double drate = 0;
// Interaktive Eingabe ausgewählt
if (ianlegen == 1) {
cout << "Anzahl der Jahre für die Zahlungsreihe:\t";
if (cin >> iyears && iyears > 0) {
vector<long int> vinv(iyears + 1);
cout << "Bitte Anschaffungswert definieren:\t";
if (cin >> ianschaffung) {
vinv.at(0) = ianschaffung;
} else {
error("Ungültige Eingabe für den Anschaffungswert.");
}
for (int i = 1; i < iyears + 1; i++) {
cout << i << ". Jahr = \t";
if (cin >> isaldo) {
vinv.at(i) = isaldo;
} else {
error("Ungültige Eingabe für saldierte Werte. Müssen positive oder negative ganze Zahlen sein.");
}
}
cout << "Bitte Interest Rate angeben:\t";
if (cin >> drate) {
vnpv.push_back(npv(vinv, drate));
} else {
error("Ungültiger Wert für die Interest Rate");
}
} else {
error("Ungültige Eingabe für die Anzahl der Jahre. Muss eine positive ganze Zahl sein.");
}
}
// Zufall-Eingabe ausgewählt
if (ianlegen == 2) {
cout << "Anzahl der Jahre für die Zahlungsreihe:\t" << endl;
if (cin >> iyears && iyears > 0) {
vnpv.push_back(npv(iyears + 1));
} else {
error("Ungültige Eingabe für die Anzahl der Jahre. Muss eine positive ganze Zahl sein.");
}
}
// Falsche Auswahl
if (ianlegen > 2 || ianlegen < 1) {
error("Werte für die Anlage eines NPV dürfen nur 1 oder 2 sein.");
}
}
#include "npv.h"
using namespace std;
int main() {
try {
// Initialisierung von Variablen
vector<npv> vnpv;
vector <long int> vinv;
bool bend = false;
int imenu = 3;
int ianlegen = 1;
int iausgabe = 0;
// Beispieleintrag Anfang
cout << "Beispiel von Wikipedia:" << endl;
vinv.push_back(-100000);
vinv.push_back(45000);
vinv.push_back(45000);
vinv.push_back(45000);
vnpv.push_back(npv(vinv, 10));
ausgabe(vnpv, iausgabe + 1);
// Beispieleintrag Ende
// Menü Anfang
while (bend == false) {
cout << endl;
cout << "Bitte wählen Sie eine der folgenden Funktionen aus:" << endl;
cout << "\t1. Neue Zahlungsreihe anlegen und berechnen" << endl;
cout << "\t2. Vorherige Zahlungsreihe anzeigen" << endl;
cout << "\t3. Programm beenden" << endl;
cout << endl;
cout << "Funktion:\t";
cin >> imenu;
if (!cin) {
error("Ungültige Eingabe für das Menü. Nur ganze pos. Zahlen zwischen 1 und 3 erlaubt.");
}
// Funktion 3 Programm beenden
if (imenu == 3) {
bend = true;
}
// Funktion 2 Bestehendes Objekt anzeigen
if (imenu == 2) {
cout << "Für welches Objekt? (Aktuell:" << vnpv.size() << ")" << endl;
cout << "Bitte Ziffer angeben:\t";
if (cin >> iausgabe) {
cout << endl;
ausgabe(vnpv, iausgabe);
} else {
error("Ungültige Eingabe für die Ausgabe.");
}
}
// Funktion 1 Neues Objekt anlegen
if (imenu == 1) {
cout << "Interaktiv anlegen (1) oder Zufallsgeneriert (2)" << endl;
cout << "Bitte Auswahl angeben:\t";
if (cin >> ianlegen) {
cout << endl;
anlegen(vnpv, ianlegen);
} else {
error("Ungültige Eingabe für Anlage eines NPV");
}
}
// Fall: Ungültige Menüauswahl
if (imenu > 3 || imenu < 1) {
error("Ungültige Eingabe für das Menü");
}
}
// Menü Ende
return 0;
} // Try Ende
// Fangen von bekannten Fehlern
catch (exception&e) {
cerr << e.what();
cout << endl;
cout << endl;
}
// Fangen von unbekannten Fehlern
catch (...) {
cerr << "Unbekannter Fehler";
cout << endl;
cout << endl;
}
}
b) Testen Sie aus einem main() Treiber, indem sie mindestens 10 Testfälle für kritische Stellen der Klasse dokumentieren, diese ausführen (Ergebnisse ebenfalls dokumentiert) und ggf. Ihren Quellcode verbessern und erneut testen. Zahlungsreihe und Zinssatz sollen wahlweise interaktiv eingegeben oder zufällig sinnvoll erzeigt werden können.
- Lösung: Die Fehleranalyse in Form eines Excel-Sheets.