|
Программирование >> Инициализация объектов класса, структура
class String { public: оператор присваивания для char* Strings operator=( const char * ); ... private: int size; char *string; уже была объявлена в нашем классе: Такой оператор реализуется следующим образом. Если объекту String присваивается нулевой указатель, он становится пустым . В противном случае ему присваивается Strings String::operator=( const char *sobj ) { sobj - нулевой указатель if (! sobj ) { size = 0; delete[] string; string = 0; else { size = strlen( sobj ); delete[] string; string = new char[ size + 1 ]; strcpy( string, sobj ); return *this; копия С-строки: string ссылается на копию той С-строки, на которую указывает sobj. Почему на копию? Потому что непосредственно присвоить sobj члену string нельзя: string = sobj; ошибка: несоответствие типов sobj - это указатель на const и, следовательно, не может быть присвоен указателю на не-const (см. раздел 3.5). Изменим определение оператора присваивания: Strings String::operator=( const *sobj ) { ... } Теперь string прямо ссылается на С-строку, адресованную sobj. Однако при этом возникают другие проблемы. Напомним, что С-строка имеет тип const char*. Определение параметра как указателя на не-const делает присваивание невозможным: car = Studebaker ; недопустимо с помощью operator=( char *) ! Итак, выбора нет. Чтобы присвоить С-строку объекту тина String, параметр должен иметь тип const char*. м1 предоставляем оператор, принимающий параметр тина const char*. Эта операция char ia[] = { d, a, n, c, e, r }; String trap = ia; trap. string ссылается на ia символов, который модифицируется способом, неизвестным объекту String. Например: ia[3] = g; а вот это нам не нужно: модифицируется и ia, и trap. string Если trap. string напрямую ссылался на ia, то объект trap демонстрировал бы своеобразное поведение: его значение может изменяться без вызова функций-членов класса String. Поэтому мы полагаем, что выделение области памяти для хранения копии значения С-строки менее опасно. Обратите внимание, что в операторе присваивания используется delete. Член string содержит ссылку на массив символов, расположенный в хипе. Чтобы предотвратить утечку, память, выделенная под старую строку, освобождается с помощью delete до выделения памяти под новую. Поскольку string адресует массив символов, следует использовать версию delete для массивов (см. раздел 8.4). И последнее замечание об операторе присваивания. Тип возвращаемого им значения -это ссылка на класс String. Почему именно ссылка? Дело в том, что для встроенных сцепление операторов присваивания int iobj, jobj; типов операторы присваивания можно сцеплять: iobj = jobj = 63; Они ассоциируются справа налево, т. е. в предыдущем примере присваивания выполняются так: iobj = (jobj = 63); Это удобно и при работе с объектами класса String: поддерживается, к примеру, String ver, noun; следующая конструкция: verb = noun = count ; При первом присваивании из этой цепочки вызывается определенный ранее оператор для const char*. Тип полученного результата должен быть таким, чтобы его можно было использовать как аргумент для копирующего оператора присваивания класса String. Поэтому, хотя параметр данного оператора имеет тип const char *, возвращается все же ссылка на String. Операторы присваивания бывают перегруженными. Например, в нашем классе String есть такой набор: Хранение в string прямой ссылки на С-строку, адресуемую sobj, порождает и иные сложности. М1 не знаем, на что именно указывает sobj. Это может быть массив набор перегруженн операторов присваивания Strings operator=( const String s ); Strings operator=( const char * ); Отдельный оператор присваивания может существовать для каждого типа, который разрешено присваивать объекту String. Однако все такие операторы должны быть определены как функции-члены класса. 15.4. Оператор взятия индекса Оператор взятия индекса operator[]() можно определять для классов, представляющих абстракцию контейнера, из которого извлекаются отдельные элементы. Примерами таких контейнеров могут служить наш класс String, класс IntArray, представленный в главе 2, или шаблон класса vector, определенный в стандартной библиотеке С++. Оператор взятия индекса обязан быть функцией-членом класса. У пользователей String должна иметься возможность чтения и записи отдельных символов члена string. Мы хотим поддержать следующий способ применения объектов String entry( extravagant ); String mycopy; for ( int ix = 0; ix < entry.size(); ++ix ) данного класса: mycopy[ ix ] = entry[ ix ]; Оператор взятия индекса может появляться как слева, так и справа от оператора присваивания. Чтобы быть в левой части, он должен возвращать l-значение #include <cassert> inine chars String::operator[]( int elem ) const { assert( elem >= 0 ss elem < size ); return string[ elem ]; индексируемого элемента. Для этого м1 возвращаем ссылку: String color( violet ); В следующем фрагменте нулевому элементу массива color присваивается символ V: color[ 0 ] = V; Обратите внимание, что в определении оператора проверяется выход индекса за границы массива. Для этого используется библиотечная С-функция assert() . Можно также возбудить исключение, показывающее, что значение elem меньше 0 или больше длины С-
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |