В первую очередь уделим внимание реализации конструкторов. У нас шесть объявленных конструкторов, седьмой — конструктор копирования — система создаст по умолчанию. Первый — конструктор без аргументов — реализован непосредственно в классе. Этот конструктор просто обнуляет поля с помощью списка инициализации. В остальных конструкторах для обнуления и заполнения массива использована стандартная функция memset (), прототип которой задан в библиотеке <cstring>.
Второй конструктор, показанный в листинге 4.3, позволяет объявить строку, присвоив ей последовательность одинаковых символов, например:
TString d ('-', 60);
Листинг 4.3. Конструктор инициализации последовательностью символов
TString::TString(const char ch, byte count)
{ TString t; // t - обнуляется
t.size = count; // количество символов
memset(t.s,ch,count); // заполнение массива
¦this = t; // копирование в текущий объект
}
В конструкторе объявлен локальный объект, который и заполняется параметрами.
Параметр-количество задан по умолчанию в прототипе, показанном в интерфейсе класса, поэтому этот же конструктор позволяет инициализировать строку единственным символом, например:
Описание основных функций библиотеки <cstring> приведено в приложении.
TString tl = '-•; TString t2 ('+');
Таким образом, этот конструктор является конструктором преобразования из chare TString. К сожалению, он «позволяет» программисту совершить ошибку, например:
TString v(48.'-'); TString w(48);
Эти объявления транслятор посчитает корректными, хотя совершенно очевидно, что программист ошибся. Тут мы опять натыкаемся на «подводный камень» С++, доставшийся в наследство от С, — неявное преобразование типов. Избавиться от этого простыми средствами нельзя, поможет только радикальная мера: определить собственный класс символов с explicit-конструкторами, чтобы запретить неявные преобразования.
Третий конструктор, текст которого приведен в листинге 4.4, — конструктор преобразования. Он позволяет объявлять и инициализировать переменные типа TString константами-строками, например:
TString d = "Строка-инициализатор": TString g("CTpoKa");
Можно в качестве аргумента задать также переменную-указатель на символьный массив, например:
char *v = "Строка-инициализатор": TString w (v): TString z = v;
Листинг 4.4. Конструктор преобразования TString::TString(const char Ss[])
{ TString t; // t - обнуляется
if (strlen(Ss) > 255) t.size = 255; // строка обрезается
else t.size = strlen(Ss); // "нормальная" длина
memcpy(t.s,Ss,t.size); // заполнили массив
¦this = t; // скопировали
}
В конструкторе проверяется длина строки-параметра. Если необходимо, то строка урезается до 255 символов.
Три других конструктора обеспечивают нам инициализацию нашей строки частью строки инициализации. Более интересным является следующий конструктор, в котором в качестве параметров указаны два указателя (листинг 4.5). Этот конструктор позволяет нам создать строку типа TString из любой подстроки символьного массива.
Листинг 4.5. Конструктор инициализации последовательностью символов
TString::TString(const char *First, const char *Last)
{ TString t; // t - обнуляется
if (First < Last) // обязательное условие
{ if (Last - First > 255) t.size = 255; // строка обрезается
else t.size = Last - First; // "нормальная" длина
memcpy(t.s,First,t.size); // заполнили массив
}
¦this = t; // скопировали
При задании аргументов обязательно выполнение условия (First < Last), то есть элемент *Last не включается в создаваемую строку. Именно такой способ задания параметров встречается в стандартной библиотеке шаблонов (Standard Template Library, STL), только в библиотеке обычно используются не указатели, а итераторы*.
Такой конструктор позволяет нам объявлять наши строки следующим образом:
char *v = "Строка-инициализатор":
TString vss(v, v+6); // vss = "Строка"
TString wss(v+7, v+strlen(v)); // wss = "инициализация"
TString tss(v+4, v+9); // tss = "ка-ин"
В качестве параметров в этом случае можно задавать любые разрешенные формы указателей. Например, можно не объявлять константу-строку, а задать ее непосредственно в качестве параметра при объявлении:
TString rr("0123456789"+3."0123456789"+6); Переменная г г получит значение «345».
Пятый конструктор позволяет нам тоже инициализировать нашу строку подстрокой символьного массива, при этом подстрока задается индексом первого символа и количеством символов. Если последний параметр используется по умолчанию, то с помощью этого конструктора мы можем задать подстроку от заданного символа до конца строки инициализации. Текст конструктора представлен в листинге 4.6.
Листинг 4.6. Конструктор инициализации подстрокой символьного массива
TString::TString(const char S[], byte index, byte count)
{ TString t(S+index, S+index+count); // все проверки
¦this - t;
}
В этом конструкторе параметры проверяются при создании локального объекта. Если параметры заданы с ошибками, то, как всегда, возвращается пустая строка.
Шестой конструктор позволяет нам инициализировать новую строку подстрокой из ранее объявленной строки (листинг 4.7).
Листинг 4.7. Конструктор инициализации из ранее объявленной строки
TString::TString(const ^String &S, byte index, byte count) { TString t;
if ( (count > S.size)|| (index+count > S.size))
t.size = S.size-index; // неправильное количество
else t.size = count; if (t.size>0)
memcpy(t.s,(S.s+index).t.size); // копируем строку
¦this = t; // заменяем текущий объект
1 Итераторы описываются в главе 6.
}
Необходимо отметить, что в конструкторах довольно серьезно проверяются параметры. Однако сообщить программе-клиенту об ошибке параметров конструктор не в состоянии — отсутствует возвращаемое значение. Если у вас есть ребенок девочка, тогда что бы она вам не мешала при программировании нужно ей показать лучшие игры для девочек тут. Здесь вы найдете разные игры для девочек например тесты - Воронины и другие.
А если мы определим лишний параметр, то у нас не будет возможности объявить объект без инициализации, и мы тем самым грубо нарушим один из принципов синтаксиса: объявление объектов новых типов не должно отличаться от объявлений встроенных типов. Решить эту проблему можно только с помощью механизма обработки исключений (см. главу 7). |