Г. Шилдт - С#4.0 Полное руководство (1160795), страница 64
Текст из файла (страница 64)
Наследование 339 Сопяо1е.кгьпеъьпе() ) Сопяо1е.итгпеъгпе("Сведения об объекте С2: "); С2.ЯЬоизсу1е () ) С2.ЯЬоиогш(); сопяо1е.ит1сеььпе("площадь равна " е 12.Атея()) В данном примере конструктор класса тг1адо1е инициализирует наследуемые члены класса тиоОБ паре вместе с его собственным полем Я О у1е. Когда конструкторы определяются как в базовом, так и в производном классе, процесс построения объекта несколько усложняется, поскольку должны выполняться конструкторы обоих классов. В данном случае приходится обращаться к еще одному ключевому слову языка С(): Ьа яе, которое находит двоякое применение: во-первых, для вызова конструктора базового класса; и во-вторых, для доступа к члену базового класса, скрывающегося за членом производного класса.
Ниже будет рассмотрено первое применение ключевого слова Ьа яе. Вызов конструкторов базовото класса С помощью формы расширенного объявления конструктора производного класса и ключевого слова Ьаяе в производном классе может быть вызван конструктор, определенный в его базовом классе. Ниже приведена общая форма этого расширенного объявления: конструктор производного класса(список параметров) : Ьаяе(список аргументов) ( тело конструктора ) где список аргументов обозначает любые аргументы, необходимые конструктору в базовом классе. Обратите внимание на местоположение двоеточия.
Для того чтобы продемонстрировать применение ключевого слова Ьаяе на конкретном примере, рассмотрим еще один вариант класса тиоОЯьаре в приведенной ниже программе. В данном примере определяется конструктор, инициализирующий свойства И1г)СЬ и Не1ОЬС. Затем этот конструктор вызывается конструктором класса Тг1апо1е. // Добавить конструктор в класс тиоОЯЬаре. пяьпэ Яуяяеш; // Класс для двумерных объектов. с1аяя ТиоОЯЬаре ( бопЬ1е рг1 игбСЬ; допбге рть Ье1ЧЬС; О Конструктор класса ТиоОЯЬаре. риЬ11с ТиоОЯЬаре(бопЬ1е и, бопЬ1е Ь) ( Игс)ПЬ Не1оьс = Ь) ) Свойства ширины и высоты объекта.
340 Часть ). Язык С№ рпЬ11с дооЬ1е ИздСЛ дес ( гесогп ргд к1дсЛ? ] яеС ( ргг издСЛ = ча1се < 0 ? -ча1ое : ча1ое; ] ) рпьздс допьзе Неь№Лс дес ( геСсгп рг1 Ле1дьс; ) яег ( ргд Лей№ЛС = ча1ие < 0 ? -ча1ие : ча1ое; ) ) рпЬ11с чо1д 5ЛоюОТщ() ( Сопяо1е.кгТСеьзпе("Ширина и высота равны " Иг№СЛ + " и " + Не1дЛС); ) ) // Класс длл треугольников, проиэводный от класса ТыоОЯЛаре. с1аяя Тгдапд1е : ТеоОЯЬаре яогзпд ЯСУ1е; // Вызвать конструктор базового класса. риЬ1дс Тг1апд1е(яггдпд я, доиЬ1е и, доиьье Л) : Ьаяе(ю, Л) ( Ясу1е = я; ) // Возвратить площадь треугольника.
роЬ11с допЫе Агеа() ( геСпгп Иь№СЛ * Не1дьг / 2? ) // Показать тип треугольника. рпЬ11с чо1д ЯЛоыЯсу1е() ( Сопяо1е.кгьгеььпе("Треугольник " ь Ясу1е)) ) Сопяо1е.кгдгеЫпе()? (" Сведения об объекте С2: "); с1аяя БЬарев4 ( яСаС1с чо1д На1п() Тгьапд1е С1 = пея Тгьапд1е С2 = пек Сопяо1е.кгОСеьдпе С1.5Лохзгу1е(); С1.5Лоебьш()) Сопяо1е.Игсгеь1пе Сопяо1е.кгдгеьдпе С2.ЯЛоеБСУ1е()) С2.ЯЛоеазш()) Сопво1е.кг1Сеьдпе ) ) Тг1апд1е("равнобедренный", 4.0, 4.0); Тг1апд1е("прямоугольный", 8.0, 12.0); (" Сведения об объекте С1: "); (" Плошадь равна " -'; С1.Агеа()); (" Площадь равна " т С2.Агеа())? Глава 11. Наследование 341 Теперь конструктор класса Тг1апо1е объявляется следующим образом. роЫьс Тг1апч1е ( яггьпэ я, бопЬ1е н, бопЬ1е Ы: Ьаяе (и, Ь) ( В данном варианте конструктор Тг1апс1е () вызывает метод Ьаяе с параметрами ы и Ь.
Это, в свою очередь, приводит к вызову конструктора Тыо()БЬаре (), инициализирующего свойства ХТбсЬ и не1сЬЬ значениями параметров и и Ь. Они больше не инициализируются средствами самого класса Тг1апс1е, где теперь остается инициализировать только его собственный член Бгу1е, определяющий тип треугольника.
Благодаря этому класс Тыо()БЬаре высвобождается для конструирования своего подобъекта любым избранным способом. Более того, в класс Тыог)БЬаре можно ввести функции, о которых даже не будут подозревать производные классы, что предотвращает нарушение существующего кода. С помощью ключевого слова Ьаяе можно вызвать конструктор любой формы, определяемой в базовом классе, причем выполняться будет лишь тот конструктор, параметры которого соответствуют переданным аргументам.
В качестве примера ниже приведены расширенные варианты классов тыопэьаре и т г( а по1е, в которые включены как используемые по умолчанию конструкторы, так и конструкторы, принимающие один аргумент. Добавить дополнительные конструкторы в класс ТноПЯЬаре. пя1пс Яуясеш? с1аяя ТноОЯЬаре ( бопЫе рть ньбсп; бопЫе рть Ье1БЬШ !/ Конструктор, выэываемый по умолчанию. рпЬ11с Тнобзпаре() Нтбгп = Неьопг = Я.О; ) Конструктор класса Тноозпаре. рпЬ11с Тнобзпаре(бопЫе н, бопЬ1е Ы ( Игбгп = н; Нетвпб = Ь; ) Сконструировать объект равной ширины и высоты.
рпЫ1с Тноб5паре(бопЬ1е х) ( Х1бСЬ = Не1ЧЬС = х? ) Свойства ширины и высоты объекта. рпЫ1с бопЫе Хьбгп ( Бег ( тегпгп ргь ньбгп; ) яег ( ргь н1бгп = ча1пе < О ? -ча1ое: ча1пе; ) рпЫьс бопЫе Не1опг ( Бег ( геготп рг1 Ье1ЧЬС; 342 Часть!. Язык С(( яея ( рг1 Ле1оЛС = ча1пе < 0 2 -ча1ое : ча1пе( ) ) роЫТс гоаб БЛон01щ() ( Сопяо1е.кг1яеь1пе(")Бирина и высота равны И1бсЛ ь " и " + Незло)' ) ) // Класс для треугольников, производный от класса ТноРЯЛаре. с1аяя Тгзапд1е : ТноРБЛаре ( ясгапд Бсу1е; /* Конструктор, используемый по умолчанию. Автоматически вызывает конструктор, доступный по умолчанию в классе ТноРЯЛаре. */ роЬ11с Тг1апп1е() ( Ясу1е = "по11"; ) // Конструктор, принимающий три аргумента.
риЫТс Тгзапд1е( яяг1пп я, бооЬ1е н, бооЬ1е Л): Ьаае (и, Ы ( Ясу1е = я; ) Сконструировать равнобедренный треугольник. рпЬ11с Тгзапд1е (бооЫе х): Ьаяе (х) ( Ясу1е = "равнобедренный"; ) // Возвратить площадь треугольника. риЬ11с бопЬ1е Агеа() ( геясгп И1НСЛ * НездЛС / 2; ) // Показать тип треугольника. рпЫТс чогб БЛонЯСу1е() ( Сопяо1е.нг1ое11пе("Треугольник " + Япу1е) ) ) с1аяя ЯЛарея5 ( аяаяас чозб Ма1п() ( Тг1апо1е С1 = пен Тг1апд1е(); Тг1апс1е С2 = пен Тг1апп1е("прямоугольный", 8.0, 12.0) Тгзапд1е СЗ = пен Тгаап01е(4.0); с1 = С2/ Сопяо1е.иг1яеРьпе("Сведения об объекте С1: "); С1. ЯЛонЯСу1е (); С1.ЯЛон01щ(); сопяо1е.игьсеыпе("площадь равна " ь с1.Агеа() ); Глава 11.
Насввдованиа 343 Сопво1е. ИгьгеЬьпе () Сопво1е.иг1геььпе("Сведения об объекте С2: "); Гг.зь зпу1е(); 12.8ьоно1щ()( Сопао1е.ыгьоевйпе("Площадь равна " + С2.йгеа()); Сопво1е.нгьгевьпе() Сопво1е.ыгьсеЬьпе("Сведения об объекте СЗ: "); СЗ.ЗЬ зпу1е() 1 13.8лоноьш(); Сопво1е.нгъгевьпе("Площадь равна " + СЗ.Ягеа())1 Сопво1е.нгьпе11пе() ) ) Вот к какому результату приводит выполнение этого кода.
Сведения об объекте с1: Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48 Сведения об объекте С2: Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48 Сведения об объекте СЗ: Треугольник равнобедренный Ширина и высота равны 4 и 4 Плошадь равна 8 А теперь рассмотрим вкратце основные принципы действия ключевого слова Ьа ве.
Когда в производном классе указывается ключевое слово Ьаве, вызывается конструктор из его непосредственного базового класса. Следовательно, ключевое слово Ьа ве всегда обращается к базовому классу, стоящему в иерархии непосредственно над вызывающим классом. Это справедливо даже для многоуровневой иерархии классов. Аргументы передаются базовому конструктору в качестве аргументов метода Ьа ее ( ) . Если же ключевое слово отсутствует, то автоматически вызывается конструктор, используемый в базовом классе по умолчанию.
Наследование и сокрытие имен В производном классе можно определить член с таким же именем, как и у члена его базового класса. В этом случае член базового класса скрывается в производном классе. И хотя формально в С№ это не считается ошибкой, компилятор все же выдаст сообщение, предупреждающее о том, что имя скрывается. Если член базового класса требуется скрыть намеренно, то перед его именем следует указать ключевое слово пеы, чтобы избежать появления подобного предупреждающего сообщения.
Следует, 344 Часть!. Язык С() однако, иметь в виду, что это совершенно отдельное применение ключевого слова пеы, не похожее на его применение при создании экземпляра объекта. Ниже приведен пример сокрытия имени. Пример сокрытия имени с наследственной связью. пз1пд Яузгеюг с1аэз А ( риЬ11с ьпс 1 = Ог ) // Создать производный класс. 1 с1ааа В : А ( пен ьпг 1) // этот член скрывает член 1 из класса А рпЬ11с В(ьпг Ь) ( 1 = Ь( // член 1 в классе В ) ровтьс коте ЯЬон() ( Сопзо1е.нг1геъьпе("Член 1 в производном классе: " + 1) ) ) с1ааа Наюенгг(гпч ( агаг1с чо1С Маьп() ( В оЬ = пен В(2)г ОЬ.ЯЬон()г ) ) Прежде всего обратите внимание на использование ключевого слова пеы в следующей строке кода. пен гпг ь; // этот член скрывает член 1 из класса А В этой строке компилятору, по существу, сообщается о том, что вновь создаваемая переменная 1 намеренно скрывает переменную 1 из базового класса А и что автору программы об этом известно.
Если же опустить ключевое слово пеы в этой строке кода, то компилятор выдаст предупреждающее сообщение. Вот к какому результату приводит выполнение приведенного выше кода. Член 1 в производном классе: 2 В классе В определветсв собственная переменная экземпляра 1, которая скрывает переменную 1 из базового класса А. Поэтому при вызове метода ЯЬоы () для объекта типа В выводится значение переменной 1, определенной в классе В, а не той, что определена в классе А.
Применение ключевого слова Ьаве для доступа к скрытому имени Имеется еще одна форма ключевого слова Ъазе, которав действует подобно ключевому слову ЬЬ1з, за исключением того, что она всегда ссылается на базовый класс Глава 11. Наследование 345 в том производном классе, в котором она используется. Ниже эта форма приведена в общем виде: Ьаяе.член где член может обозначать метод или переменную экземпляра. Эта форма ключевого слова Ьа эе чаще всего применяется в тех случаях, когда под именами членов производного класса скрываются члены базового класса с теми же самыми именами.
В качестве примера ниже приведен другой вариант иерархии классов из предыдущего примера. Применение ключевого слова Ьаэе для преодоления препятствия, связанного с сокрытием имен. пя1пч Яуэгеьо с1ааэ А рпЫьс ьпс 1 = О; /! Создать производный класс. с1ааа В : А ( пен ьпг Ю // этот член скрывает член 1 иэ класса А рпЫьс в(1пс а, 1пс Ы ( Ьаяе.ь = а; // здесь обнаруживается скрытый член иэ класса А = Ь; // член 1 иэ класса В ) рпЫьс тсьй Збон() ( // Здесь выводится член 1 иэ класса А. Сопэо1е.игьпеъьпе("Член 1 в базовом классе: " ь Ьаэе.1)) О А здесь выводится член 1 иэ класса В. Сопяо1е.игьпеъипе("Член 1 в производном классе: " + 1); ) с1аэя Ппсонегкаюе ( агагьс яоьб Маьп() ( В оЬ = пен В(1, 2); сЬ.Звон(): ) Выполнение этого кода приводит к следующему результату.