// Implementation of a simple string class. #include "Str.h" #include #include using std::cout; using std::endl; using std::ostream; // Print trace messages with object addresses to show when methods are called. #define TRACE(what) cout << "- Str::" what << " called on " << this << endl // constructors Str::Str() { TRACE("default constructor"); // allocate empty string st_ = new char[1]; st_[0] = '\0'; } Str::Str(const char *s) { TRACE("c-string constructor"); int len = strlen(s); st_ = new char[len+1]; strcpy(st_, s); } Str::Str(const Str &s) { TRACE("copy constructor"); int len = strlen(s.st_); st_ = new char[len+1]; strcpy(st_, s.st_); } // destructor Str::~Str() { TRACE("destructor"); delete[] st_; } // operations int Str::length() const { TRACE("length"); return strlen(st_); } char* Str::c_str() const { TRACE("c_str"); char * result = new char[strlen(st_)+1]; strcpy(result, st_); return result; } void Str::append(const Str& s) { TRACE("append"); char *newst = new char[strlen(st_) + strlen(s.st_) + 1]; strcpy(newst, st_); strcat(newst, s.st_); delete[] st_; st_ = newst; } Str& Str::operator=(const Str &s) { TRACE("assignment"); // do nothing if trying to assign a string to itself if (this == &s) { return *this; } // Replace string array with one of correct size // (Note: this is where the self-assignment test _really_ matters) // (Note: a better implementation would re-use the existing array // if it's long enough, but not too long) delete[] st_; st_ = new char[strlen(s.st_)+1]; // copy characters and return strcpy(st_, s.st_); return *this; } // stream output // (Note: not a member function of Str. This is an overloaded global // function that is a friend of Str so it can access private data) ostream &operator<<(ostream &out, const Str &s) { out << s.st_; return out; }