#include "String.h" namespace cse374 { String::String() { makeNewRaw(0); raw_[0] = '\0'; } String::String(const String& other) : String(other.raw_) {} String::String(const char* raw) { if (raw == NULL) { throw std::runtime_error("String cannot be null"); } makeNewRaw(strlen(raw)); strcpy(raw_, raw); } String::~String() { delete [] raw_; } String& String::operator=(const String& other) { if (this == &other) { return *this; } delete [] raw_; makeNewRaw(strlen(other.raw_)); strcpy(raw_, other.raw_); return *this; } size_t String::length() const { return strlen(raw_); } void String::append(const String& other) { char* old = raw_; makeNewRaw(length() + other.length()); strcpy(raw_, old); strcat(raw_, other.raw_); delete [] old; } void String::clear() { raw_[0] = '\0'; } std::ostream& operator<<(std::ostream& out, const String& s) { return out << s.raw_; } void String::makeNewRaw(size_t length) { raw_ = new char[length + 1]; } } int main() { cse374::String s = "foo"; // conversion operator - on the stack. std::cout << s << std::endl; cse374::String* s2 = new cse374::String("bar"); // normal - on the heap. cse374::String s3("baz"); // normal constructor call - on the stack. s = s3; // assignment operator s.append(*s2); std::cout << s << std::endl; std::cout << s3 << std::endl; // s3 was unchanged by assignment or append. return 0; }