В этом примере описание класса выделено в отдельный файл.
// файл _string_.h:
#include <string.h>
#include <iostream>
#include <assert.h>
using namespace std;
class String
{
char* str; // указатель на строку
int len; // длина строки
// операторные функции ввода-вывода строки:
friend istream& operator >> (istream&, String&);
friend ostream& operator << (ostream&, String&);
public:
String() //Конструктор по умолчанию
{ str = NULL; len=0;}
String(char *); //Основной конструктор
String(const String &); //Конструктор копирования
int GetLength() {return strlen(str);} // количество символов строки
int GetMem() {return len;} // объем памяти, выделенный для символов // строки
~String(){ delete [] str;} // деструктор
// операторные функции:
String& operator += (const String&);
String operator + (const String&);
String& operator = (const String&);
char& operator [](int i);
String operator () (int, int); //Подстрока
};
//Определение функций:
// функция ввода:
istream& operator >> (istream& is, String& st)
{
char *tmp = new char[129];
/* используем временную строку, поскольку заранее неизвестно, сколько символов будет введено */
is.getline(tmp, 128);
st = String(tmp);
delete []tmp;
return is;
}
// функция вывода:
|
|
ostream& operator << (ostream& os, String& st)
{
os << st.str;
return os;
}
// основной конструктор:
String::String(char* source)
{
len = strlen(source);
str = new char[len+1];
strcpy(str, source);
}
// конструктор копирования:
String::String(const String& source)
{
len = source.len;
str = new char[len + 1]; /* конструктор создает новый объект, поэтому освобождение ранее выделенной памяти не требуется */
strcpy(str, source.str);
}
// оператор присваивания:
String& String::operator = (const String& source)
{
if (&source!= this) //Проверка самоприсваивания
{
len = source.len;
if (str) delete []str; // освобождаем ранее выделенную память
str = new char[len+1];
strcpy(str,source.str);
}
return *this; // возвращаем текущий объект
}
// операция += (добавляет строку к текущему объекту):
String& String::operator += (const String& source)
{
len = len + source.len;
char* tmp = new char[len+1]; // выделяем память для суммы строк
strcpy(tmp, str); // копируем символы текущего объекта
strcat(tmp, source.str); // добавляем символы второй строки
if (str) delete [] str; // освобождаем память, ранее выделенную текущему объекту
str = tmp; // новая строка становится основой объекта
return *this; // функция возвращает текущий объект
}
// операция +:
String String:: operator + (const String& str2)
{
String str1(str); // создаем временный объект, чтобы не изменять текущий
str1 += str2; // используем уже запрограммированную операцию +=
return str1; // возвращаем временный объект
}
/*операция [], которая позволяет считывать и изменять символы строки, используя номер символа: */
char& String::operator [](int i)
/*тип функции обязательно должен быть ссылкой, иначе невозможно будет изменять символы */
{
assert(i>=0 && i<len); /*функция assert() проверяет условие и, если оно не выполняется, выводит сообщение об ошибке и останавливает работу программы */
|
|
return str[i];
}
/*операция (), которая будет выбирать из строки подстроку, начиная с символа с заданным номером index; длина подстроки определяется параметром count */
String String:: operator () (int index, int count)
{
String sub;
if (index <= len-1) // проверяем, не выходит ли индекс за границы строки
{
int ost = len-index;
// определяем, сколько символов осталось до конца строки
sub.len = count>ost? ost: count;
/* если запрошенное количество символов больше, чем имеется, то функция вернет имеющийся остаток строки */
sub.str = new char[sub.len+1]; // выделяем память
strncpy(sub.str, str+index, count); // копируем сиволы
sub.str[sub.len]='\0';
// функция strncpy() не дописывает признак конца строки
}
return sub;
}
// файл string.cpp:
#include <iostream>
#include <conio.h>
#include <windows.h>
#include "_string_.h"
using namespace std;
int main()
{
//Настройки шрифтов и региональных стандартов:
if(SetConsoleCP(1251)==0)
//проверка правильности установки кодировки символов для ввода
{
cerr<<"Fialed to set codepage!"<<endl;
/* если не удалось установить кодовую страницу, вывод сообщения об ошибке */
}
if(SetConsoleOutputCP(1251)==0)//тоже самое для вывода
{
cerr<<"Failed to set OUTPUT page!"<<endl;
}
do
{
String s1, s2; // исходная и результирующая строки
cout<<"Введите строку: ";
cin>>s1;
int len=s1.GetLength();
if (len)
{
unsigned n;
cout << "На сколько символов сдвинуть строку? ";
cin>>n;
n %= len; /* в результате циклического сдвига на длину строки, она принимает исходное состояние, поэтому имеет смысл выполнять сдвиг только на число, равное остатку от деления n на длину строки */
cout << "Результат:\n";
s2 = s1(n, len-n) + s1(0,n);
// в результате сдвига влево первые n символов уходят в конец строки
cout <<s2<<endl;
/* проверим соответствие выделяемой под строку памяти и количества символов строки (они должны быть равны): */
cout << "длина " << s2.GetLength() <<
" память: " << s2.GetMem() << endl;
}
} while (_getch()!= 27);
return 0;
}