000
23.03.2006, 10:05 Uhr
ref
|
Der Code:
C++: |
// Invariants #define DEBUG #define SHOW_INVARIANTS #include <iostream> #include <string.h>
#ifndef DEBUG #define ASSERT(x) #else #define ASSERT(x) \ if (! (x)) \ { \ std::cout << "FEHLER!! Annahme " << #x << " nicht zutreffend\n"; \ std::cout << " in Zeile " << __LINE__ << "\n"; \ std::cout << " in Datei " << __FILE__ << "\n"; \ } #endif
class String { public: // Konstruktoren String(); String(const char *const); String(const String &); ~String();
char & operator[](int offset); char operator[](int offset) const;
String & operator= (const String &); int GetLen()const { return itsLen; } const char * GetString() const { return itsString; } bool Invariants() const;
private: String (int); // Privater Konstruktor char * itsString; unsigned short itsLen; };
// Standardkonstruktor erzeugt String von 0 Bytes Länge String::String() { itsString = new char[1]; itsString[0] = '\0'; itsLen=0; ASSERT(Invariants()); }
// Privater (Hilfs-) Konstruktor, nur von Klassen- // methoden für das Erzeugen eines neuen Strings der // erforderlichen Größe verwendet. Mit Null gefüllt. String::String(int len) { itsString = new char[len+1]; for (int i = 0; i<=len; i++) itsString[i] = '\0'; itsLen=len; ASSERT(Invariants()); }
// Konvertiert ein Zeichen-Array in einen String String::String(const char * const cString) { itsLen = strlen(cString); itsString = new char[itsLen+1]; for (int i = 0; i<itsLen; i++) itsString[i] = cString[i]; itsString[itsLen]='\0'; ASSERT(Invariants()); }
// Kopierkonstruktor String::String (const String & rhs) { itsLen=rhs.GetLen(); itsString = new char[itsLen+1]; for (int i = 0; i<itsLen;i++) itsString[i] = rhs[i]; itsString[itsLen] = '\0'; ASSERT(Invariants()); }
// Destruktor, gibt reservierten Speicher frei String::~String () { ASSERT(Invariants()); delete [] itsString; itsLen = 0; }
// Gleich-Operator, gibt vorhandenen Speicher frei, // kopiert dann String und Größe String& String::operator=(const String & rhs) { ASSERT(Invariants()); if (this == &rhs) return *this; delete [] itsString; itsLen=rhs.GetLen(); itsString = new char[itsLen+1]; for (int i = 0; i<itsLen;i++) itsString[i] = rhs[i]; itsString[itsLen] = '\0'; ASSERT(Invariants()); return *this; }
// Nicht-konstanter Offset-Operator, gibt Referenz // auf Zeichen zurück, das sich damit ändern // lässt! char & String::operator[](int offset) { ASSERT(Invariants()); if (offset > itsLen) return itsString[itsLen-1]; else return itsString[offset]; ASSERT(Invariants()); }
// Konstanter Offset-Operator für konstante // Objekte (siehe Kopierkonstruktor!) char String::operator[](int offset) const { ASSERT(Invariants()); if (offset > itsLen) return itsString[itsLen-1]; else return itsString[offset]; ASSERT(Invariants()); }
// Sicherstellen, dass der String eine bestimmte Länge hat, oder // der Zeiger ist NULL und die Länge ist null. bool String::Invariants() const { #ifdef SHOW_INVARIANTS std::cout << " String OK "; #endif return ( (itsLen && itsString) || (!itsLen && !itsString) ); }
class Animal { public: Animal():itsAge(1),itsName("John Q. Animal") {ASSERT(Invariants());} Animal(int, const String&); ~Animal(){} int GetAge() { ASSERT(Invariants()); return itsAge;} void SetAge(int Age) { ASSERT(Invariants()); itsAge = Age; ASSERT(Invariants()); } String& GetName() { ASSERT(Invariants()); return itsName; } void SetName(const String& name) { ASSERT(Invariants()); itsName = name; ASSERT(Invariants()); } bool Invariants(); private: int itsAge; String itsName; };
Animal::Animal(int age, const String& name): itsAge(age), itsName(name) { ASSERT(Invariants()); }
bool Animal::Invariants() { #ifdef SHOW_INVARIANTS std::cout << " Animal OK "; #endif return (itsAge > 0 && itsName.GetLen()); }
int main() { Animal sparky(5,"Sparky"); std::cout << "\n" << sparky.GetName().GetString() << " ist "; std::cout << sparky.GetAge() << " Jahre alt."; sparky.SetAge(8); std::cout << "\n" << sparky.GetName().GetString() << " ist "; std::cout << sparky.GetAge() << " Jahre alt."; return 0; }
|
verlauf:
string const char *const konstruktor String OK string const char *const konstruktor ende
kopiekonstruktor
char string[] operator const start String OK zurueck
char string[] operator const start String OK zurueck
char string[] operator const start String OK zurueck
char string[] operator const start String OK zurueck
char string[] operator const start String OK zurueck
char string[] operator const start String OK zurueck String OK
kopiekonstruktor ende
Animal konstruktor2 Animal OK Animal konstruktor2 ende
stringdestruktor String OK stringdestruktor ende
string&getname start Animal OK string&getname ende
Sparky ist Animalgetage Animal OK Animalgetage ende 5 Jahre alt. voidsetage start Animal OK Animal OK voidsetage ende
string&getname start Animal OK string&getname ende
Sparky ist Animalgetage Animal OK Animalgetage ende 8 Jahre alt.
stringdestruktor String OK stringdestruktor ende
der frage: scauen wir erstmal main() ,da befindet:
C++: |
Animal sparky(5,"Sparky");
|
zu animal-konstruktor zuerst geht nicht:
C++: |
Animal::Animal(int age, const String& name): itsAge(age), itsName(name) { ASSERT(Invariants()); }
|
es muss const String& name behandelt werden .. das führt zu string konstruktor es hat aber beide aufgerufen:
C++: |
String(const char *const); String(const String &);
|
ich bin der meinung dass nur der zweite passt also(kopiekonstruktor) die frage warum der erste auch statt gefunden ????? -- Man kann ein Problem nicht mit der gleichen Denkweise lösen, mit der es erschaffen wurde. (Albert Einstein) |