// string.cpp - implements class String // (from Learning C++: A Hands on Approach, by Eric Nagler) // entered/tested by cmc, 8/12/03 - reorganized 10/30/13 #include "string.h" #include #include #include #include using namespace std; // global functions with friend status String const join(String const &left, String const &right) { int lengthLeft = strlen(left.ptrChars); int lengthRight = strlen(right.ptrChars); char *buffer = new char[lengthLeft + lengthRight + 1]; strcpy(buffer, left.ptrChars); strcat(buffer, right.ptrChars); String newString(buffer); delete [] buffer; return newString; } void display(String const &string) { cout << string.ptrChars; } String const operator+ (String const &left, String const &right) { return join(left, right); // uses join from chapter 8 } ostream &operator<< (ostream &out, String const &s) { return out << s.ptrChars; } // constructors and destructor String::String(char const *chars) { chars = chars ? chars : ""; ptrChars = new char[strlen(chars) + 1]; strcpy(ptrChars, chars); ++count; } String::String(char ch) { ptrChars = new char[2]; ptrChars[0] = ch; ptrChars[1] = '\0'; ++count; } String::String(String const &str) { ptrChars = new char[strlen(str.ptrChars) + 1]; strcpy(ptrChars, str.ptrChars); ++count; } String::~String() { delete [] ptrChars; --count; } // member features bool String::search(String const &target) const { if (strstr(ptrChars, target.ptrChars)) return true; return false; } unsigned String::count = 0; // static definition of instance counter unsigned String::getCount() { return count; } void upperCase(char *str) { // utility function used by toUpper for (size_t i = 0; i < strlen(str); ++i) str[i] = static_cast(toupper(str[i])); } String String::toUpper() const { String newInstance(*this); upperCase(newInstance.ptrChars); return newInstance; } String &String::refresh(char const *chars) { // returns reference for chaining size_t newLength = strlen(chars); if (strlen(ptrChars) != newLength) { delete [] ptrChars; ptrChars = new char[newLength + 1]; } strcpy(ptrChars, chars); return *this; } // member operators String &String::operator= (String const &other) { // exception-safe version from Nagler p. 268 if (strlen(ptrChars) != strlen(other.ptrChars)) { char *ptrHold = new char[strlen(other.ptrChars) + 1]; delete [] ptrChars; // note: does not happen if new throws exception ptrChars = ptrHold; } strcpy(ptrChars, other.ptrChars); return *this; } int String::operator()(char const *chars) const { int count = 0; int size = strlen(chars); int tests = strlen(ptrChars) - size + 1; for (int i = 0; i < tests; i++) if (!strncmp(ptrChars + i, chars, size)) ++count; return count; } char &String::operator[] (unsigned index) throw(char const *) { // mutator if (index >= strlen(ptrChars)) throw "Subscript out of range"; return ptrChars[index]; } char String::operator[] (unsigned index) const throw(char const *) { // const if (index >= strlen(ptrChars)) throw "Subscript out of range"; return ptrChars[index]; } String &String::operator+= (String const &other) { return *this = *this + other; // uses binary operator+ } String &String::operator++ () { // prefix version for (unsigned i = 0; i < strlen(ptrChars); ++i) ++ptrChars[i]; return *this; } String const String::operator++ (int) { // postfix version String copy(*this); ++(*this); // calls prefix version return copy; }