Habs noch etwas verbessert (hatte auch Fehler drinn) und Kommentare eingefügt.
adresse.cpp:
Code:
#include <string>
#include <iostream>
#include <list>
/* selber gschriebener header: */
#include "conversions.hpp"
using namespace std;
/*
Ich hab statt der struct glaich ne Klasse gmacht. Ist C++ net C. ;)
Klassen haben viele Vorteile (schalg im netzt, z.B. aud de.wikipedia.org unter OOP nach).
Die hier genutzten Vorteile sind aber nur das ich Methoden habe für den Zugriff.
Also das sind Funktionen die fix an ein Objekt von Typen Adresse gebunden sind.
Ein weiterer Vorteil ist das man alle möglichen operatoren für eine Klasse überladen klann.
So kannst du z.B. eine art von Zahlen Klasse schreiben und alle Mathem. Operatoren überladen.
Dann kannst du mit +, -, ++, --, /, *, += usw. so arbeiten, wie mit ner normalen Zahl. ;)
Hier hab ich nur den << und >> operator für die Ein-/Ausgabe überladen.
*/
class Adresse
{
public:
/*
Ich hab auch den c++ String std::string verwendet.
Der ist natürlich auch ne Klasse und hat alle notwendigen operatoren überladen (+, +=, = usw.)
*/
string name;
string vname;
string ort;
string strasse;
unsigned int plz;
unsigned int hsnr;
/*
Hier sind die Konstruktoren.
Die werden Aufgerufen, wenn ein neues Objekt der Klasse angelegt wird.
Je nach dem mit welchen Parameter (oder überhaupt mit einen) das Objekt
angelegt wird, wird der entsprechende Konstruktor aufgerufen.
Leerkonstruktor:
*/
Adresse()
: name(),
vname(),
ort(),
strasse(),
plz( 0 ),
hsnr( 0 ) {}
/* "normaler" Konstuktor: */
Adresse( const string & name,
const string & vname,
const string & ort,
const string & strasse,
unsigned int plz,
unsigned int hsnr )
: name( name ),
vname( vname ),
ort( ort),
strasse( strasse ),
plz( plz ),
hsnr( hsnr ) {}
/* Copy-Konstruktor:
Wird z.B. in dem Fall aufgerufen:
Adresse adr1;
Adresse adr2 = adr1;
*/
Adresse( const Adresse & a )
: name( a.name ),
vname( a.vname ),
ort( a.ort),
strasse( a.strasse ),
plz( a.plz ),
hsnr( a.hsnr ) {}
/* Der Zuweisungsoperator:
Wird z.B. in dem Fall aufgerufen:
Adresse adr1;
Adresse adr2;
...
adr2 = adr1;
*/
Adresse & operator = ( const Adresse & a ) {
if( this != &a ) {
name = a.name;
vname = a.vname;
ort = a.ort;
strasse = a.strasse;
plz = a.plz;
hsnr = a.hsnr;
}
return *this;
}
/*
Mit der Methode lese ich von einer Shell:
*/
void prompt( istream & is = cin, ostream & os = cout, ostream & err = cerr ) {
string line;
bool input_ok = false;
os << "name: " << flush;
getline( is, name );
trim( name );
os << "vname: " << flush;
getline( is, vname );
trim( vname );
os << "ort: " << flush;
getline( is, ort );
trim( ort );
os << "strasse: " << flush;
getline( is, strasse );
trim( strasse );
input_ok = false;
while( !input_ok ) {
os << "plz: " << flush;
getline( is, line );
try {
plz = parse_number< unsigned int >( trim( line ) );
input_ok = true;
}
catch( domain_error & e ) {
err << "*** error: " << e.what() << endl;
}
}
input_ok = false;
while( !input_ok ) {
os << "hsnr: " << flush;
getline( is, line );
try {
hsnr = parse_number< unsigned int >( trim( line ) );
input_ok = true;
}
catch( domain_error & e ) {
err << "*** error: " << e.what() << endl;
}
}
}
/*
Hiermit lese ich von ner Datei:
*/
void read( istream & is ) {
string line;
/*
* Die Funktion trim() hab ich auch selbst geschrieben.
* Sie löscht alle fürenden und endenden Leerzeichen/Tabs/Zeilenwechsel/...
* aus dem string raus.
*
* siehe: conversions.hpp
*/
getline( is, name ); trim( name );
getline( is, vname ); trim( vname );
getline( is, ort ); trim( ort );
getline( is, strasse ); trim( strasse );
/* ich versuche den input mit meiner template funktion
* parse_number< unsigned int > in ein unsinged int umzuwandeln.
* (siehe: conversions.hpp)
*
* falls das fehlschlägt wird die exception domain_error geworfen.
* das fange ich mit diesem try {} catch() {} block ab, und dann
* setzte ich das failbit im istream, um zu makieren, das was beim
* lesen schief gelaufen ist.
*/
try {
getline( is, line );
plz = parse_number< unsigned int >( trim( line ) );
getline( is, line );
hsnr = parse_number< unsigned int >( trim( line ) );
}
catch( domain_error & ) {
is.setstate( is.rdstate() | ios_base::failbit );
}
}
/*
Und damit gebe ich so auf ne Datei aus, das ich's mit read() wieder lesen kann.
Das const nach der Methodendeklaration bedeutet, das man diese Methode auch auf
konstanten Objekten aufrufen kann, da ja nix im Objekt verändert wird.
*/
void write( ostream & os ) const {
os << name << endl
<< vname << endl
<< ort << endl
<< strasse << endl
<< plz << endl
<< hsnr << endl;
}
};
/* der Input-Operator */
istream & operator >> ( istream & is, Adresse & a ) {
a.read( is );
return is;
}
/* der Output-Operator */
ostream & operator << ( ostream & os, const Adresse & a ) {
a.write( os );
return os;
}
int main( void ) {
Adresse adresse;
list< Adresse > adressen;
string line;
bool answer_ok = false;
bool do_read = true;
while( !cin.eof() && do_read ) {
adresse.prompt();
adressen.push_back( adresse );
answer_ok = false;
while( !answer_ok ) {
cout << endl
<< "weiter? [J/N] " << flush;
getline( cin, line );
trim( line );
if( toupper( line[ 0 ] ) == 'J' ) {
answer_ok = true;
}
else if( toupper( line[ 0 ] ) == 'N' ) {
do_read = false;
answer_ok = true;
}
}
cout << endl;
}
for( list< Adresse >::const_iterator iter = adressen.begin(), end = adressen.end();
iter != end;
++ iter ) {
cout << *iter;
}
return 0;
}
In folgender von mir verfassten headerfile sind templates verwendet. Die erklär ich jetzt aber nicht. Verwende einfach die Funktionen draus (wie ich's tat in adresse.cpp) wenn du willst. Betrachte all meinen in diesen Thread geposteten Code als BSD Lizenziert.
conversions.hpp:
Code:
#ifndef CONVERSIONS_HPP__
#define CONVERSIONS_HPP__
#include <stdexcept>
#include <cstdio>
#include <cctype>
std::string & trim( std::string & str ) {
std::string::size_type i = 0;
std::string::size_type len = 0;
while( std::isspace( str[ i ] ) ) ++ i;
str.erase( 0, i );
len = str.size();
if( len > 0 ) {
i = len - 1;
// str[ 0 ] darf kein whitespace sein, sonst wär ja len == 0
while( i > 0 && std::isspace( str[ i ] ) ) -- i;
str.erase( i + 1 );
}
return str;
}
inline std::string trim( const std::string & str ) {
return trim( std::string( str ) );
}
inline std::string trim( const char * str ) {
return trim( std::string( str ) );
}
template< typename number_type >
number_type parse_number( const char * str );
template< typename number_type >
inline number_type parse_number( const std::string & str ) {
return parse_number< number_type >( str.c_str() );
}
template< typename number_type >
number_type _parse_number( const char * str, const char * fmt ) {
size_t n = 0;
number_type ret = 0;
int count = std::sscanf( str, fmt, &ret, &n );
if( count <= 0 || std::strlen( str ) > n )
throw std::domain_error( "Parameter has not a number format." );
return ret;
}
template<>
inline int parse_number< int >( const char * str ) {
return _parse_number< int >( str, "%d%n" );
}
template<>
inline short int parse_number< short int >( const char * str ) {
return _parse_number< short int >( str, "%hd%n" );
}
template<>
inline long int parse_number< long int >( const char * str ) {
return _parse_number< long int >( str, "%ld%n" );
}
template<>
inline long long parse_number< long long >( const char * str ) {
return _parse_number< long long >( str, "%lld%n" );
}
template<>
inline unsigned int parse_number< unsigned int >( const char * str ) {
return _parse_number< unsigned int >( str, "%u%n" );
}
template<>
inline unsigned short int parse_number< unsigned short int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%hu%n" );
}
template<>
inline unsigned long int parse_number< unsigned long int >( const char * str ) {
return _parse_number< unsigned long int >( str, "%lu%n" );
}
template<>
inline unsigned long long parse_number< unsigned long long >( const char * str ) {
return _parse_number< unsigned long long >( str, "%llu%n" );
}
template<>
inline float parse_number< float >( const char * str ) {
return _parse_number< float >( str, "%f%n" );
}
template<>
inline double parse_number< double >( const char * str ) {
return _parse_number< double >( str, "%lf%n" );
}
template<>
inline long double parse_number< long double >( const char * str ) {
return _parse_number< long double >( str, "%llf%n" );
}
template< typename number_type >
inline number_type parse_oct( const char * str );
template< typename number_type >
inline number_type parse_oct( const std::string & str ) {
return parse_oct< number_type >( str.c_str() );
}
template<>
inline unsigned short int parse_oct< unsigned short int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%ho%n" );
}
template<>
inline unsigned int parse_oct< unsigned int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%o%n" );
}
template<>
inline unsigned long int parse_oct< unsigned long int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%lo%n" );
}
template<>
inline unsigned long long parse_oct< unsigned long long >( const char * str ) {
return _parse_number< unsigned short int >( str, "%llo%n" );
}
template< typename number_type >
inline number_type parse_hex( const char * str );
template< typename number_type >
inline number_type parse_hex( const std::string & str ) {
return parse_hex< number_type >( str.c_str() );
}
template<>
inline unsigned short int parse_hex< unsigned short int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%hx%n" );
}
template<>
inline unsigned int parse_hex< unsigned int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%x%n" );
}
template<>
inline unsigned long int parse_hex< unsigned long int >( const char * str ) {
return _parse_number< unsigned short int >( str, "%lx%n" );
}
template<>
inline unsigned long long parse_hex< unsigned long long >( const char * str ) {
return _parse_number< unsigned short int >( str, "%llx%n" );
}
#endif // CONVERSIONS_HPP__
Lesezeichen