Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 56
Текст из файла (страница 56)
По традиции полубайт обозначает целое значение без знака. В приведенном ниже примере программы тип полубайтовых данных реализуется с помощью класса иуьь|е. В качестве базового для него используется тип апь, но с ограничением на хранение данных от О до 15. В классе ИуЬЬ1е определяются следующие операторы.
° Сложение двух объектов типа иуьь1е. ° Сложение значения типа ьпг с объектом типа ИуьЬ1е. ° Сложение объекта типа иуьь1е со значением типа йпю ° Операции сравнения: больше (>) и меньше (<). ° Операция инкремента. ° Преобразование значения типа ъпс в объект типа иуьь1е. ° Преобразование объекта типа иуьь1е в значение типа Ьпс. Глава в. Перегрузка операторов 285 Перечисленных выше операций достаточно, чтобы показать, каким образом тип класса Нуьые интегрируется в систему типов СФ.
Но для полноценной реализации этого типа данных придется определить все остальные доступные для него операции. Попробуйте ~делать это сами в качестве упражнения. Ниже полностью приводится класс МуЬЫе, а также класс МуЬЫепешо, демонстрирующий его применение. // Создать 4-разрядный, полубайтовый тип данных // под названием НуЬЫе. ия1пд Зуякешг // 4-разрядный тип данных.
с1аяя НуЬЫе ( гпс ча1; // базовый тип для хранения данных риЬ1гс ИуЬЬ1е() ( ча1 = Ог ) риЫьс НуЬЫе(гпс г) ( ча1 = 1г ча1 = ча1 6 Охгг // сохранить 4 младших разряда // Перегрузить бинарный оператор + для сложения // двух объектов типа МуЬЬ1е. риЫгс ягагьс НуЬЫе орегагог ь (НуЬЬ1е ор1, НуЬЬ1е ор2) ( НуЬЫе геяи1Г = пен НуЬЫе () г геяи1г.ча1 = ор1.ча1 т ор2.ча1) геяи1к.ча1 = геяи1г.ча1 а Охуг // сохранить 4 младших разряда гегигп геяи1г; // Перегрузить бинарный оператор ь для сложения // объекта типа НуЬЫе и значения типа гпс. риЫ1с ясасгс НуЬЬ1е орегаког +(НуЬЬ1е ор1, 1пс ор2) ( НуЬЬ1е геяи1Г = пен НуЬЫе(): геяи1г.ча1 = ор1.ча1 + ор24 геяи1к.ча1 = геяи1с.ча1 4 Оху; // сохранить 4 младших разряда гесигп геяи1Г; ) // Перегрузить бинарный оператор + для сложения // значения типа 1пс и объекта типа МуЬЬ1е.
риЫгс ясакгс НуЬЫе орегагог +(гпс ор1, НуЬЫе ор2) ( 286 Часть!, язык С» МуЬЫе геви1с = пен МуЬЬ1е()т геви1С.ча1 = ор1 + ор2.ча1) геви1С.ча1 = 'геви1С.ча1 й Оху) // сохранить 4 младших разряда гегигп геви1Ст ) // Перегрузить оператор ++. риЫ1с вгаггс МуЬЫе орегагог ++(МуЬЫе ор) ( МуЬЫе геви1С = пею МуЬЫе() т геви1г.ча1 = ор.ча1 т 1; гези1с.ча1 = геви1с.ча1 й Охут // сохранить 4 младших разряда гегигп геви1Ст ) // Перегрузить оператор >. риЬ11с вгаС1с Ьоо1 орегагог >(МуЬЬ1е ор1, МуЬЬ1е ор2) ( 1<(ор1.ча1 > ор2.ча1) гегигп Сгиет е1ве гегигп Еа1ве) ) // Перегрузить оператор <. риЫ1с вгаггс Ьоо1 орегагог <(МуЬЫе ор1, МуЬЫе ор2) ( 1г(ор1.ча1 < ор2.ча1) гегигп Сгие) е1ве гегигп Йа1вет ) // Преобразовать тип МуЬЫе в тип 1пг.
риЫгс вгаЫс мвр11с1С орегагог апС (МуЬЫе ор) ( гегигп ор.ча1: ) // Преобразовать тип 1пг в тип МуЬЫе. риЫас вгаггс 1шр11саС орегагог МуЬЫе (ЬЬС ор) ( гегигп печ МуЬЫе(ор)т ) с1азв МуЬЫепешо ( вгаггс чогб Ма1п() ( МуЬЬ1е а = пею МуЬЫе(1)т МуЬЬ1е Ь = пен МуЬЬ|е(10)т МуЬЬ1е с = пен МуЬЫе()т гпс ст Глава 9. Перегрузка операторов 287 Сопео1е.иг).кеЫпе("а: " + (апк) а) Г Сопео1е.иг1кеу.аде("Ь: " + (1пк) Ы г // Использовать тип ИуЬЫе в условном операторе 11.
та(а < Ы Сопзо1е.Игасепапе("а меньше Ып")г // Сложить два объекта типа ИУЬЫе. с = а ь ь! сопзо1е.игагет апе("с после операции с = а е ь| " + (1пг) с) ) // Сложить значение типа апс с объектом типа ИуЬЫе. а ъ= 5) Сопео1е.иг1сепапе("а после операции а += 5т " + (апг) а) Сопео1е.нг1кепапе()г // Использовать тип НуЬЫе в выражении типа апс. к=а*2+Зг Сопзо1е.иг1кеЫпе("Результат вычисдения выражения а * 2 + 3: " + Г)г Сопзо1е.игасепапе()г // Продемонстрировать присваивание значения // типа апг и переполнение. а = 19; Сопзо1е.Игасе01пе( "Результат присваивания а = 19т " + (апс) а) Сопзо1е.игакеаапЕ()г // Испольэовать тип ИуЬЫе для управления циклом.
Сопзо1е.игакетапе("Управление циклом гог " + "с помощью объекта типа ИУЬЬ1е."); гог(а = О) а < 10г а+т.) сопзо1е.иг1ге((1пг) а + " ")г Сопзо1е.игасепапе()Г ) При выполнении этой программы получается следуютций результат: а: 1 Ьт 10 а меньше Ь с после операции с = а + Ь. "11 а после операции а += 5: 8 Результат вычисления выражения а * 2 + Зт 15 Результат присваивания а = 19т 3 Управление циклом Гог с помощью объекта типа ИуЬЫе.
0123456789 288 Часть Ь йзнг С№ Большая часть функций класса НуЬЫе не требует особых пояснений. Тем не менее необходимо подчеркнуть ту особую роль, которую операторы преобразования играют в интегрировании класса типа нуЬЫе в систему типов С№. В частности, объект типа нуЬЫе можно свободно сочетать с данными других типов в арифметических выражениях, поскольку определены преобразования объекта этого типа в тип 1пс и обратно. Рассмотрим для примера следующую строку кода из приведенной выше программы: с=а*г~з; В этом выражении переменная с и значения 2 и 3 относятся к типу хпс, но в ней присутствует также объект типа НуЬЫе.
Оба типа оказываются совместимыми благодаря неявному преобразованию типа нуьые в тип 1пс. В данном случае остальная часть выражения относится к типу №вт, поэтому объект а преобразуется в тип №вС с помощью своего метода преобразования. А благодаря преобразованию типа №пс в тип нуЬЫе значение типа №пс может быть присвоено объекту типа нуЬЪ1е. Например, в следующей строке из приведенной выше программы: сначала выполняется оператор преобразования типа Ьвс в тип нуьые.
Затем создается новый объект типа нуьые, в котором сохраняются 4 младших разряда целого значения 19, а по существу, число 3, поскольку значение 19 превышает диапазон представления чисел для типа нуЬЫе. Далее этот объект присваивается переменной экземпляра а. Без операторов преобразования подобные выражения были бы просто недопустимы. Кроме того, преобразование типа нуЬЫе в тип нуЬЫе используется в цикле гол. Без такого преобразования организовать столь простой цикл гол было бы просто невозможно. 290 Часть !. язык Сз где тип элемента обозначает конкретный тип элемента индексатора.
Следовательно, у каждого элемента, доступного с помощью индексатора, должен быть определенный тип элемента. Этот тип соответствует типу элемента массива. Параметр индекс получает конкретный индекс элемента, к которому осуществляется доступ. Формально этот параметр совсем не обязательно должен иметь тип 1пс, но поскольку индексаторы, как правило, применяются для индексирования массивов, то чаще всего используется целочисленный тип данного параметра. В теле индексатора определены два аксессора (т.е.
средства доступа к данным): дес и зес. Аксессор подобен методу, за исключением того, что в нем не объявляется тип возвращаемого значения или параметры. Аксессоры вызываются автоматически при использовании индексатора, и оба получают индекс в качестве параметра. Так, если индексатор указывается в левой части оператора присваивания, то вызывается аксессор зес и устанавливается элемент, на который указывает параметр индекс. В противном случае вызывается аксессор дег и возвращается значение, соответствующее параметру индекс.
Кроме того, аксессор зес получает неявный параметр ча1це, содержащий значение, присваиваемое по указанному индексу. Преимущество индексатора заключается, в частности, в том, что он позволяет полностью управлять доступом к массиву, избегая нежелательного доступа. В качестве примера рассмотрим программу, в которой создается класс Га115огтйггау, реализующий массив для выявления ошибок нарушения границ массива, а следовательно, для предотвращения исключительных ситуаций, возникающих во время выполнения в связи с индексированием массива за его границами.
Для этого массив инкапсулируется в качестве закрытого члена класса, а доступ к нему осуществляется только с помощью индексатора. При таком подходе исключается любая попытка получить доступ к массиву за его границами, причем эта попытка пресекается изящно и без катастрофических последствий для программы.
А поскольку в классе Га115оутйггау используется индексатор, то к массиву можно обращаться с помощью обычной формы записи. О Использовать индексатор ддя создания // отказоустойчивого массива. пз1пц 5увсев) с1азв Га115отсйггау ! ьпк]] а) // ссылка ка базовый массив рцвььс ьпк Ьепякн) // открытая переменная длины массива рцв11с Ьоо1 ЕггГ1ад) // обозначает результат последней операции // Построить массив заданного размера. рцнььс Га115огкйггау(1пк зьзе) ! а = пеы 1пк)зьзе]) Ьеппкп = зьке; // Зто ипдексатор для класса Га115огсйккау. рцв11с 1пс кньз]ьпс ьпбек] ! // Это аксессор дес.