#include #include #include #include // strlen strdup strcpy strncpy strcat #define T printf("%s: body=%s allocated=%zu zzz=%d\n", __PRETTY_FUNCTION__, body, allocated, zzz) class str { public: str(const char *val = "") { body = strdup(val); allocated = strlen(body)+1; T; } explicit str(size_t size) { // Только явный конструктор body = (char *)calloc(size+1, sizeof(char)); allocated = size+1; } ~str() { zzz++; T; free(body); } void print() const { printf("[allocated=%zu %s]\n", allocated, body); } str & operator= (const str &b) { free(body); body = strdup(b.body); allocated = b.allocated; T; return *this; } str(const str &b) { body = strdup(b.body); allocated = b.allocated; T; } str operator+ (const str &b) const { size_t need = strlen(body) + strlen(b.body) + 1; str ret(""); ret.body = (char *)realloc(ret.body, need); assert(ret.body != nullptr); strcpy(ret.body, body); strcat(ret.body, b.body); ret.allocated = strlen(ret.body)+1; T; return ret; } str & operator+=(const str &b) { size_t need = strlen(body) + strlen(b.body) + 1; char *new_body = (char *)malloc(need); assert(new_body != nullptr); strcpy(new_body, body); strcat(new_body, b.body); allocated = need; free(body); body = new_body; T; return *this; } char const & operator[] (size_t ind) const { T; if (ind >= allocated) { char buf[100]; sprintf(buf, "Index %zu is out of range [0..%zu)", ind, allocated); throw str(buf); } return body[ind]; } char & operator[] (size_t ind) { T; if (ind >= allocated) { char buf[100]; sprintf(buf, "Index %zu is out of range [0..%zu)", ind, allocated); throw str(buf); } return body[ind]; } //char operator[](size_t ind, char val) { // body[ind] = val; // return val; //} size_t size() { return allocated - 1; } const char *c_str() const { return body; } // Метод класса без объекта класса! static int get_zzz() { // Не видны body и allocated. Видно только zzz. return zzz; } private: char *body; // C-string, null-terminated "123" -> '1', '2', '3', 0 size_t allocated; static int zzz; }; int str::zzz; // Статические переменные класса должны быть инициализированы // вне класса void foo(str const &c, size_t ind) { printf("foo!:%c\n", c[ind]); } int main() { try { str a("abra"); // Сработал явный конструктор (const char *) //a = a + "cadabra"; a = str("cadabra") + a; //str b; // b = 100; // Сработал неявный конструктор (size_t) //b = str(100); // Здесь конструктор явный // str c = a + b; for (size_t i = 0; i < a.size(); i++) { printf("a[%zu]=%c\n", i, a[i]); } a[0] = 'A'; foo(a,-1); str bar(100); bar[0] = 'F'; bar[1] = 'o'; bar[2] = 'o'; bar.print(); str c("shvabra"); str d; d = c += "12345"; } catch (str const &arg) { printf("Caught '%s'\n", &arg[0]); } printf("totl destructors of str = %d\n", str::get_zzz()); }