// 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 functions get 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]; strncpy(st_, s, len + 1); } Str::Str(const Str& s) { TRACE("copy constructor"); int len = strlen(s.st_); st_ = new char[len + 1]; strncpy(st_, s.st_, len + 1); } // 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"); int len = strlen(st_); char* result = new char[len + 1]; strncpy(result, st_, len + 1); return result; } void Str::append(const Str& s) { TRACE("append"); int len1 = strlen(st_); int len2 = strlen(s.st_); char* newst = new char[len1 + len2 + 1]; strncpy(newst, st_, len1 + 1); strncat(newst, s.st_, len2); 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_; int len = strlen(s.st_); st_ = new char[len + 1]; // copy characters and return strncpy(st_, s.st_, len + 1); 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; }