Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
//: C16:Sstring.h // Stack-based string #ifndef SSTRING_H #define SSTRING_H #include <cstring> #include <iostream> template<int bsz = 0> class SString { char buf[bsz + 1]; char* s; public: SString(const char* S = "") : s(buf) { if(!bsz) { // Make on heap s = new char[strlen(S) + 1]; std::strcpy(s, S); } else { // Make on stack buf[bsz] = 0; // Ensure 0 termination std::strncpy(s, S, bsz); } } SString(const SString& rv) : s(buf) { if(!bsz) { // Make on heap s = new char[strlen(rv.s) + 1]; std::strcpy(s, rv.s); } else { // Make on stack buf[bsz] = 0; std::strncpy(s, rv.s, bsz); } } SString& operator=(const SString& rv) { // Check for self-assignment: if(&rv == this) return *this; if(!bsz) { // Manage heap: delete s; s = new char[strlen(rv.s) + 1]; } // Constructor guarantees length < bsz: std::strcpy(s, rv.s); return *this; } ~SString() { if(!bsz) delete []s; } int operator==(const SString& rv) const { return ! stricmp(s, rv.s); // nonstandard } int operator!=(const SString& rv) const { return stricmp(s, rv.s); } int operator>(const SString& rv) const { return stricmp(s, rv.s) > 0; } int operator<(const SString& rv) const { return stricmp(s, rv.s) < 0; } char* str() const { return s; } friend std::ostream& operator<<(std::ostream& os, const SString<bsz>& S) { return os << S.s; } }; typedef SString<> Hstring; // Heap string #endif // SSTRING_H ///:~
//: C16:Integer.h // An int wrapped in a class #ifndef INTEGER_H #define INTEGER_H #include <iostream> class Integer { int i; public: // Guaranteed zeroing: Integer(int ii = 0) : i(ii) {} operator int() const { return i; } const Integer& operator++() { i++; return *this; } const Integer operator++(int) { Integer returnval(i); i++; return returnval; } Integer& operator+=(const Integer& x) { i += x.i; return *this; } friend std::ostream& operator<<(std::ostream& os, const Integer& x){ return os << x.i; } }; #endif // INTEGER_H ///:~