Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 63
Текст из файла (страница 63)
В данном случае более подходящим решением оказалось применение свойств, чтобы управлять доступом, а не предотвращать его. Таким образом, модификатор доступа ргогесгеб следует применять в том случае, если требуется создать член класса, доступный для всей иерархии классов, но для остального кода он должен быть закрытым. А для управления доступом к значению члена класса лучше воспользоваться свойством. Конструкторы и наследование В иерархии классов допускается, чтобы у базовых и производных классов были свои собственные конструкторы.
В связи с этим возникает следующий резонный вопрос: какой конструктор отвечает за построение объекта производного класса: конструктор базового класса, конструктор производного класса или же оба вместе? На этот вопрос можно ответить так: конструктор базового класса конструирует базовую часть объекта, а конструктор производного класса — производную часть этого объекта. И в этом есть своя логика, поскольку бвзовому классу неизвестны и недоступны любые элементы производного класса, а значит, их конструирование должно происходить раздельно. В приведенных выше примерах данный вопрос не возникал, поскольку они опирались на автоматическое создание конструкторов, используемых в С(Г по умолчанию.
Но на практике конструкторы определяются в большинстве классов. Ниже будет показано, каким образом разрешается подобная ситуация. Если конструктор определен только в производном классе, то все происходит очень просто: конструируется объект производного класса, а базовая часть объекта автоматически конструируется его конструктором, используемым по умолчанию. В качестве примера ниже приведен переработанный вариант класса тг1апо1е, в котором определяется конструктор, а член Ясу1е делается закрытым, так как теперь он устанавливается конструктором. // Добавить конструктор в класа тгьаоч1е. ов1од Бувсевс // Класс для двумерных объектов, с1ввв тиовэьвре ( боовге рг1 игбСЬ; бооъге ргь Ле1соо/ 324 Часть ), ))зык С» // Свойства ширины и длины объекта.
рцЬ1»с боцЬ1е ИТНСЬ ( дев ( гесцгп р<1 <161Ь/ ) яев ( рг» и1НСЬ = ча1це < 0 ? -ча1це: ча1це; ) рцЬ11с боцЬ1е НеадЬС ( дев ( гесцгп рта Ье1дЬС? ) яео ( рг» Ье»дно = ча1це < 0 ? -ча1це: ча1це; ) ) рцЬ11с чогб БноиР»ш() ( Сопяо1е.ыг11е11пе("Ширина и длина равны " + и1бсь + " и " т не1двс)) ) ) //.Класс для треугольников, производный от // класса ТноРБЬаре. с1азя Тг1апд1е: ТноРБЬаре ( яог1пд Бсу1е? // Конструктор. рцЬ11с Тг1апд1е(ясг1пд я, боцЬ1е и, боцЬ1е Ь) ( ИТНСЬ = и) // инициализировать член базового класса Не1днс = Ь? // инициализировать член базового класса Бцу1е = я; // инициализировать член производного класса ) // Возвратить площадь треугольника. рцЬ11с боцЬ1е йгеа() ( геоцгп ИТНСЬ * Не»дно / 2; // Показать тип треугольника.
рцЬ11с чотб БЬонБСу1е() ( Сопяо1е.нгаоеЬ»пе("Треугольник " + Бсу1е)? ) ) с1аяя БЬареяЗ ( яоав1с чо10 Ма»п() ( Тг»апд1е С1 = пен Тг»апд1е( "равнобедренный", 4.0, 4.0)) Тгаапд1е С2 = пен Тг»апд1е( "прямоугольный", 8.0, 12.0); Сопяо1е.Иг1це1»пе("Сведения об объекте 11: ")? С1.БЬоюзсу1е()? 11. БЬокраш (); Сопяо1е.Игасе11пе("Площадь равна " + 11.)(геа())? Глава )). Иаследаввнве 325 Сопзо1е. Игъгеъъпе (); Сопзо1е.иг1геъапе (" Сведения об объекте С2: «) ~ 12 . 5Лонзг у1е (); С2.5Лонсаш(); сопзо1е . иг1сеъг пе (" площадь равна " + с2 .йгеа () ); ) ) В данном примере конструктор класса тг1ап51е инициализирует наследуемые члены класса тмопзларе вместе с его собственным полем Ясу1е. Когда конструкторы определяются как в бззовом, так и в производном классе, процесс построения объекта несколько усложняется, поскольку должны выполняться конструкторы обоих классов.
В данном случае приходится обращаться к еще одному ключевому слову языка С№к Ьаве, которое находит двоякое применение: во-первых, для вызова конструктора базового класса; и во-вторых, для доступа к члену базового класса, скрывающегося за членом производного класса. Ниже будет рассмотрено первое применение ключевого слова Ьаае. Вызов конструкторов базового класса С помощью формы расширенного объявления конструктора производного класса и ключевого слова Ьаве в производном классе может быть вызван конструктор, определенный в его базовом классе. Ниже приведена общая форма этого расширенного объявления. конструктор производного класса ( список параметров): Ьаве(список аргументов) ( // тело конструктора ) где список аргументов обозначает любые аргументы, необходимые конструктору в базовом классе. Обратите внимание на местоположение двоеточия. Для того чтобы продемонстрировать применение ключевого слова Ьазе на конкретном примере, рассмотрим еше один вариант класса тно05ларе в приведенной ниже программе.
В данном примере определяется конструктор, инициализирующий свойства и1бсл и не1олс. Затем этот конструктор вызывается конструктором класса тг1апд1е. // добавить конструктор в класс Тнопзпаре. ов1пд Яувгешв // Класс для двумерных объектов. с1азв Тноп5Ларе ( бооЬ1е ргг н1бгп; бооЫе ргг Ле1ЧЛсв // Конструктор класса Тноозпаре. риЬ11с Тнопзпаре(боиЬ1е и, бооЬ1е Л) ( И1бСЛ = нв Не15ЛС = Л; ) // Свойства ширины и высоты объекта.
роЫТс бопЫе Игбсп ( 326 Часть (. Яэык Са цег ( гесогп ргг и1бспк ) яег ( рг1 и1дгь = иа1ие < 0 ? -та1пе к та1пе( ] ) роЬ1гс бопЬ1е Не10ЬГ ( Пес [ гесигп рг1 Ье10ЬГ( ) яес [ ргг Ье10ЬГ = ча1не < 0 ? -та1пе: иа1пе( ) ) риЪ11с чогб 5поибкщ() ( Сопяо1е.ыг1се11пе("Ширина и высота равны " + И1бсп + " и " + Не10ЬГ) к ) ) // Класс для треугольников, производный от // класса ТиоОЯЬаре. с1аяя Тгаапц1е: Тио05паре ( ясг[п0 5гу1ек // Вызвать конструктор базового класса.
рпЫгс Тгаап01е( ягг1пд я, бопЫе и, бопЬ1е Ь) : Ьаяе(и, Ы ( Ясу1е я) ! // Возвратить площадь треугольника. рпЫТс бопЫе Агеа() [ гесогп Игбсп * Не10ЬГ / 2) ) // Показать тип треугольника. рпЫТс то1б япоиягу1е() ( Сопяо1е.ыг1ге11пе("Треугольник " + Ясу1е)к ) с1аяя 5парея4 ( ягасас тоаб На1п() ( тг1ап01е г1 = пеи Тг[апд1е("равнобедренный", 4.0, 4.0)( тг1апд1е г2 = пеи тг1ап01е("прямоугольный", 8.0, 12.0)( Сопяо1е.иг1ге11пе("Сведения об объекте Г1к и); Г1.5поиЯГу1е()к Г1.5поиРТщ(); сопяо1е.иг1геп1пе("площадь равна " + г1.Агеа())т Сопяо1е.ыг1се11пе() сопяо1е.игггепапе("сведения об объекте г2к ")т Г2.ЯЬоиасу1е(); Г2.
ЯпоиВТщ () к сопяо1е.игагеьапе("площадь равна " + г2.Агеа()); ) Глава 11. Наследование 327 Теперь конструктор класса тг1апо1е объявляется следующим образом: риЫ1с Тгтап01е( зггтпд з, боиЬ1е н, боиЬ1е Ы : Ьазе(н, Ы ( В данном варианте конструктор тг1апо1е () вызывает метод Ьазе с параметрами н и Ь.
Это, в свою очередь, приводит к вызову конструктора тно((5ьаре (), инициализирующего свойства н1с(гь и не1оьг значениями параметров н и ь. Они больше не инициализируются средствами самого класса тг1апо1е, где теперь остается инициализировать только его собственный член Ягу1е, определяющий тип треугольника. Благодаря этому класс тно()ЯЬаре высвобождается для конструирования своего подобъекта любым избранным способом. Более того, в класс тно()ЯЬаре можно ввести функции, о которых даже не будут подозревать производные классы, что предотвращает нарушение кода. С помощью ключевого слова Ьазе можно вызвать конструктор любой формы, определяемой в базовом классе, причем выполняться будет лишь тот конструктор, параметры которого соответствуют переданным аргументам.
В качестве примера ниже приведены расширенные варианты классов тмоРяьаре и тг1апо1е, в которые включены как используемые по умолчанию конструкторы, так и конструкторы, принимающие один аргумент. // Добавить дополнительные конструкторы // в класс тноЬЯЬаре. из1по Яузсешг с1азз Тновзпаре ( боиЫе рг1 нсбгпл боиЫе рст Ье10ЬС? // Конструктор, вызываемый зо умолчанию. риЫ1с ТноРЯЬаре() ( Итбгп = НеТЧЬС = 0.0; ) // Конструктор класса Тнобзпаре. риЬ11с Тнобзпаре(боиЬ1е н, боиЬ1е Ь) ( набов = и; Не1дпс = Ьг // Сконструировать объект равной ширины и высоты.
риЬ11с Тнобзпаре(боиЫе х) ( Ньбгп = Не1ЧЬС = х; ) // Свойства ширины и высоты объекта. риЫ1с боиЬ1е И1бСЬ ( дег ( гегигп ргс наПСЬ? зег ( рст набСЬ = ча1ие < 0 ? -ча1ие: ча1ие/ ) риЫ1с боиЫе НетдЬС ( 328 Часть (. Язык С» дес ( гесвгп ргг ьесдьст ) яег ( ргг Пе1дЬС = ча1це < 0 ? -ча1ие: ча1чет ) ) рпЬ11с чогб БпоиОью() ( сопяо1е.иг1сесгпе("ширина и высота равны " ь и1бсь.+ " и " + не1дьс)т ) ) // Класс для треугольников, производный от // класса ТиоОБЬаре. с1аяя Тггапд1е: Тиобзпаре ( ягг1пд Бсу1ет /* Конструктор, используеыый по умолчанию.
Автоматически вызывает конструктор, доступньв» по умолчанию в классе ТчоОБПаре. */ рвЬ1гс Тг1апд1е() ( Бгу1е = "пи11"; ) // Конструктор, принимающий три аргумента. риЫгс Тггапд1е( ° ясг1пд я, бопЬ1е и, бовЫе Ы : Ьаяе(и, Ы ( БСУ1е = ят ) // Сконструировать равнобедренный треугольник. рпЫгс Тггапд1е (бопЬ1е х) т Ьаяе(х) ( БСу1е = "равнобедренный"; ) // Возвратить площадь треугольника.
риЬ11с бопЬ1е Агеа() ( гегпгп И1бСЬ * Негдпс / 2т ) // Показать тип треугольника. риЬ1гс чо10 БпоиЯСу1е() ( Сопяо1е.Игггесгпе("Треугольник " Ь БСу1е)т ) с1аяя Бпарея5 ( ягаггс чокб Магд() ( тг1апд1е с1 = пен тггапд1е()т Тггапд1е С2 = пеи Тггапд1е("прямоугольньпк", 8.0, 12.0); Тг1апд1е СЗ = пеи Тггапд1е(4.0)т с1 = с2; Сопяо1е.ыгггеОТпе("Сведения об объекте С1: "); С1.БЬо БСУ1е()т Глава ((. Ивследоввние 329 Ст.злонотщ()4 Сопяо1е.Игхсепхпе("Площадь равна " + С1.агеа()); Сопво1е.иг1вепхпе(] Сопво1е.иг1теьтпе("Сведения об объекте С2: "); СЗ.БЬонзпу1е()4 С2.БЬондтщ(); сопяо1е.игхсепвпе("площэдь равна " ь с2.лгеа())4 Сопео1е .Игхьесхпе () Сопво1е.игхтеввпе("Сведения об объекте СЗ: ")) СЗ.БЬОНБСУ1Е() 4 СЗ.БЬонввщ(); Сопяо1е.игтвесхпе("Площадь равна " + СЗ.Лгеа())4 Сопяо1е.иг1веь1пе() 4 ) Вот к какому результату приводит выполнение этого кода: Сведения об объекте С1: Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48 Сведения об объекте С2: Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48 Сведения об обьекте сЗ: Треугольник равнобедренный Ширина и высота равны 4 и 4 Площадь равна 8 А теперь рассмотрим вкратце основные принципы действия ключевого слова ьаэе.