Г. Шилдт - С#4.0 Полное руководство (1160795), страница 56
Текст из файла (страница 56)
Язык б№ Вывести координаты х, т, Е. роЬ11с чогб ВЬон() ( Сопво1е.Хгтсеоьпе(х т ", " ь у + ", " ь г); ) ) с1авв ТЬгееооезо ( згастс чогг( Наьп() ( ТЬгеео а = пен ТЬгееО(1, 2, 3)г ТЬгееО Ь = пен ТЬгееО(10, 10, 10)) ТЬгеео с = пен ТЬгеео(); гпс Сопво1е.нгьсе("Координаты точки а: "); а.5ьон () г Сопзо1е.нггсеьгпс(); Сопво1е.нггсе("Координаты точки Ь: "); Ь.5Ьон(); Сопао1е.Хггсеоьпе(); с = а + Ь! // сложить координаты точек а и Ь Сопво1е.нггсе("Результат сложения а + Ь: "); с.зьон(); Сопво1е.нгггеоьпе()г Г) а; // преобразовать в тип 1пс явно, поскольку указано приведение типов .Иг1сеьгпе("Результат присваивания 1 = а: " + 1) .Хггсеоьпе()," (ьп Сопво1е Сопво1е — (ьпг)а * 2 — (ьпг)ьг // явно требуется приведение типов Сопво1е.Хгггеььпе("Результат вычисления выражения а * 2 — Ь: " + 1) (ьпС) аг // преобразовать в тип 1пг явно, поскольку указано приведение типов На операторы преобразования накладывается ряд следующих ограничений.
° Исходный или целевой тип преобразования должен относиться к классу, для которого объявлено данное преобразование. В частности, нельзя переопределить преобразование в тип 1пс, если оно первоначально указано как преобразование в тип с(опЬ1е. ° Нельзя указывать преобразование в класс оЬз ест или же из этого класса. ° Для одних и тех же исходных и целевых типов данных нельзя указывать одновременно явное и неявное преобразование. Оператор преобразования теперь указан в явной форме, и поэтому преобразование должно быть явно приведено к типу 1пс.
Например, следующая строка кода не будет скомпилирована, если исключить приведение типов. Глава 9. Перегрузка операторов 297 ° Нельзя указывать преобразование базовшо класса в производный класс. 1Подробнее о базовых и производных классах речь пойдет в главе 11.) ° Нельзя указывать преобразование в интерфейс или же из него. (Подробнее об интерфейсах — в главе 12.) Помимо указанных вьпце ограничений, имеется ряд рекомендаций, которыми обычно руководствуются при выборе операторов явного или неявного преобразования.
Несмотря на все преимущества неявных преобразований, к ним следует прибегать только в тех случаях, когда преобразованию не свойственны ошибки. Во избежание подобных ошибок неявные преобразования должны быть организованы только в том случае, если удовлетворяются следующие условия. Во-первых, информация не теряется, например, в результате усечения, переполнения или потери знака.
И вовторых, преобразование не приводит к исключительной ситуации. Если же неявное преобразование не удовлетворяет этим двум условиям, то следует выбрать явное преобразование. Рекомендации и ограничения по перегрузке операторов Действие перегружаемого оператора распространяется на класс, для которого он определяется, и никак не связано с его первоначальным применением к данным встроенных в С№ типов. Но ради сохранения ясности структуры и удобочитаемости исходного кода перегружаемый оператор должен, по возможности, отражать основную суть своего первоначального назначения. Например, назначение оператора + для класса т)тгее(г по сути не должно заметно отличаться от его назначения для целочисленных типов данных.
Если бы, например, определить оператор + относительно некоторого класса таким образом, чтобы по своему действию он стал больше похожим на оператор А то вряд ли от этого было бы много проку. Главный принцип перегрузки операторов заключается в следующем: несмотря на то, что перегружаемый оператор может получить любое назначение, ради ясности новое его назначение должно быть так или иначе связано с его первоначальным назначением.
На перегрузку операторов накладывается ряд ограничений. В частности, нельзя изменять приоритет любого оператора или количество операндов, которое требуется для оператора, хотя в операторном методе можно и проигнорировать операнд. Кроме того, имеется ряд операторов, которые нельзя перегружать. А самое главное, что перегрузке не подлежит ни один из операторов присваивания, в том числе и составные, как, например, оператор +=. Ниже перечислены операторы, которые нельзя перегружать. Среди них имеются и такие операторы, которые будут рассматриваться далее в этой книге. с)тескег) ав с)е1ас1С а1зео№ 15 пеи цпс)тес)гес) Суреог Несмотря на то что оператор приведения () нельзя перегружать явным образом, имеется все же возможность создать упоминавшиеся ранее операторы преобразования, выполняющие ту же самую функцию.
298 Часть!. Язык С№ Ограничение, связанное с тем, что некоторые операторы, например +ьь нельзя перегружать, на самом деле не является таким уж непреодолимым. Вообще говоря, если оператор определен как перегружаемый и используется в составном операторе присваивания, то обычно вызывается метод этого перегружаемого оператора. Следовательно, при обращении к оператору += в программе автоматически вызывается заранее объявленный вариант метода оре та 0 о ге ( ) . Например, в приведенном ниже фрагменте кода метод орегасог+ () автоматически вызывается для класса ТЬгееО, а в итоге объект Ь будет содержать координаты П, 12, 13.
Тпгеео а = пеи Тптеео(1, 2, 3)1 ТЬгеео Ь = пеи ТЬгееО(10, 10, 10); Ь += а," УУ сложить координаты точек а и Ь И последнее замечание: несмотря на то, что оператор индексации массива ( ] нельзя перегружать с помощью операторного метода, имеется возможность создать индексаторы, о которых речь пойдет в следующей главе. Еще один пример перегрузки операторов Во всех предыдущих примерах программ, представленных в этой главе, для демонстрации перегрузки операторов использовался класс ТЬгееР, и этой цели он служил исправно. Но прежде чем завершить эту главу, было бы умеспю рассмотреть еще один пример перегрузки операторов. Общие принципы перегрузки операторов остаются неизменными независимо от применяемого класса, тем не менее, в рассматриваемом ниже примере наглядно демонстрируются сильные стороны такой перегрузки, особенно если это касается расширяемости типов.
В данном примере разрабатывается 4-разрядный целочисленный тип данных и для него определяется ряд операций. Вам, вероятно, известно, что на ранней стадии развития вычислительной техники широко применялся тип данных для обозначения 4-разрядных двоичных величин, называвшихся полубайтами, поскольку они составляли половину байта, содержали одну шестнадцатеричную цифру и были удобны для ввода кода полубайтами с пульта ЭВМ, что в те времена считалось привычным занятием для программистов! В наше время этот тип данных применяется редко, но он по-прежнему является любопытным дополнением целочисленных типов данных в С№.
По традиции полубайт обозначает целое значение без знака. В приведенном ниже примере программы тип полубайтовых данных реализуется с помощью класса ыуЬЬ1е. В качестве базового для него используется тип Тпг, но с ограничением на хранение данных от 0 до 15. В классе ЫуЬЬ1е определяются следующие операторы. ° Сложение двух объектов типа )(уЬЬ1е. ° Сложение значения типа 1пг с объектом типа нуЬЬ1е.
° Сложение объекта типа ыуЬЬ1е со значением типа Тпг.. ° Операции сравнения: больше (>) и меньше (<). ° Операция инкремента. ° Преобразование значения типа Тпь в объект типа ыуьь1е. ° Преобразование объекта типа ыуЬЬ1е в значение типа 1п г. Глава 9. Перегрузка операторов 299 // Создать полубайтовый тип 4-разрядных данных под названием МуЪЫе.
иягпо Буягевя тип4-разрядных данных. с1аяя МуЬЬ1е ( гпг на1! // базовый тип для хранения данных рпЬ1гс МуЬЬ1е() ( на1 = Ог ) риЫ1с МуЬЫе (гпг г) на1 = г) на1 = на1 б Охгг // сохранить 4 младших разряда Перегрузить бинарный оператор е для сложения двух объектов тина МуЬЬ1е. рпЫ1с яСаггс МуЬЫе орегагог + (МуЬЫе ор1, МуЬЫе ор2) ( МуЬЬ1е геяо1С = пен МуЬЬ1е(); гевп1с.на1 = ор1.на1 а ор2.на1; геяп1с.на1 = геяп1с.на1 ь Охег // сохранить 4 младших разряда гесогп геяп1гг ) // Перегрузить бинарный оператор + для сложения // объекта типа МуЬЬ1е и значения типа 1пС.
роЫтс яСаггс МуЬЫе орегагог +(МуЬЫе ор1, гпС ( МуЬЫе геяп1С = пен МуЬЬ1е(); ор2) геян1с.на1 = ор1.на1 + ор2; геяо1с.на1 = геяо1с.на1 я Охрг // сохранить 4 ыладших разряда гегогп геяп1С; ) Перегрузить бинарный оператор + для сложения // значения типа гпг и объекта типа МуЬЬ1е. рпЬ1гс ягаггс МуЬЫе орегагог т(гпг ор1, МуЬЬ1е ( МуЬЫе геяп1С = пен МуЬЬ1е()г ор2) геяо1С.на1 = ор1 т ор2.на1; Перечисленных выше операций достаточно, чтобы показать, каким образом тип класса МуЬЫе интегрируется в систему типов С№.
Но для полноценной реализации этого типа данных придется определить все остальные доступные для него операции. Попробуйте сделать это сами в качестве упражнения. Ниже полностью приводится класс МуЬЬ1е, а также класс МуЬЬ1еРешо, демонстрирующий его применение. 300 Часть!. Язык С() гевн1ыча1 = гевп1г.ча1 в Охр; // сохранить 4 младших разряда геаогп гевп1Ы ) // Перегрузить оператор рпь11с вса<1с муьь1е орегагог ++(хуьь1е ор) ( ИуЬЬ1е геяп1Г = пен МуЬЪ1е()) гевп1г.ча1 = ор.ча1 + 1; гево1о.ча1 = гево1с.ча1 в Охр) // сохранить 4 младших разряда геспгп гево1Г; ) Перегрузить оператор >.
роЬ11с вгаг1с Ьоо1 орегагог >(МуЬЬ1е ор1, МуЬЬ1е ор2) ( 11(ор1.ча1 > ор2.ча1) гегигп сгое; е1ве геонгп га1ве; ) Перегрузить оператор <. роЬ11с всасгс Ьоо1 орегасог <(МуЬЬ1е ор1, МуЬЬ1е ор2) ( 1<(ор1.ча1 < ор2.ча1) гегпгп ггое; е1яе гесогп йа1ве) Преобразовать тип ИуЬЪ1е в тип гпс. роЫгс воав1с 1шр11с1С орегасог 1пв (НуЬЫе ор) ( гесогп ор.ча1) ) // Преобразовать тип 1пв в тип МуЬЬ1е.