Перегружаемые методы класса
Управление доступом к членам класса.
Хотя в действительности дело обстоит несколько сложнее, но по сути существуют
два базовых типа членов класса: открытые и закрытые. К открытому члену класса мо-
жет свободно получить доступ код, определенный вне этого класса. К закрытому же члену класса доступ могут
получить методы, определенные только в этом классе. Благодаря использованию за-
крытых членов класса мы и имеем возможность управлять доступом.
Ограничение доступа к членам класса — это фундаментальная часть объектно-
ориентированного программирования, поскольку она предотвращает неверное ис-
пользование объекта. Управление доступом к членам класса достигается за счет использования четырех
спецификаторов доступа: public, private, protected и internal .
Модификатор protected применяется только при включении интерфейсов и описан в главе 9. Модификатор i n t e r n a l применяется в основном при использовании компоновочных
файлов (assembly) Спецификатор public разрешает доступ к соответствующему члену класса со сто-
роны другого кода программы, включая методы, определенные внутри других классов.
Спецификатор p r i v a t e разрешает доступ к соответствующему члену класса только
для методов, определенных внутри того же класса. Таким образом, методы других
классов не могут получить доступ к private-члену не их класса. Члены, которые используются только внутри класса, следует определить как
закрытые.
2. Данные экземпляров, которые должны находиться в пределах заданного диапа-
зона, следует определить как закрытые, а доступ к ним обеспечить через от-
крытые методы, выполняющие проверку вхождения в диапазон.
3. Если изменение члена может вызвать эффект, распространяющийся за преде-
лы самого члена (т.е. действует на другие аспекты объекта), этот член следует
определить как закрытый и обеспечить к нему контролируемый доступ.
4. Члены, при некорректном использовании которых на объект может быть ока-
зано негативное воздействие, следует определить как закрытые, а доступ к ним
обеспечить через открытые методы, предохраняющие эти члены от некоррект-
ного использования.
5. Методы, которые получают или устанавливают значения закрытых данных,
должны быть открытыми.
6. Объявление переменных экземпляров открытыми допустимо, если нет причин
делать их закрытыми.
10. Конструкторы класса: по умолчанию, с аргументами, копирующие.
Конструктор инициализирует объект при его создании. Он имеет такое же имя,
что и сам класс, а синтаксически подобен методу. Однако в определении конструкто-
ров не указывается тип возвращаемого значения. Формат записи конструктора такой:
доступ имя_класса{) {
// тело конструктора}
Все классы имеют конструкторы независимо от того, определите вы их или нет,
поскольку С# автоматически предоставляет конструктор по умолчанию, который
инициализирует все переменные-члены, имеющие тип значений, нулями, а перемен-
ные-члены ссылочного типа — пи 11-значениями. Но если вы определите собствен-
ный конструктор, конструктор по умолчанию больше не используется.
В предыдущем примере использовался конструктор без параметров. Но чаще при-
ходится иметь дело с конструкторами, которые принимают один или несколько пара-
метров. Параметры вносятся в конструктор точно так же, как в метод: для этого дос-
таточно объявить их внутри круглых скобок после имени конструктора.
Часто при разработке класса используют специальный вид конструктора, который называется копирующий конструктор. Копирующий конструктор применяется для создания клона объекта.
Перегружаемые методы класса.
В С# два или больше методов внутри одного класса могут
иметь одинаковое имя, но при условии, что их параметры будут различными. Такую
ситуацию называют перегрузкой методов (method overloading), а методы, которые в ней
задействованы, — перегруженными (overloaded). Перегрузка методов — один из спосо-
бов реализации полиморфизма в С#.
В общем случае для создания перегрузки некоторого метода достаточно объявить
еще одну его версию. Об остальном позаботится компилятор. Но здесь необходимо
отметить одно важное условие: все перегруженные методы должны иметь списки па-
раметров, которые отличаются по типу и/или количеству. Методам для перегрузки не-
достаточно отличаться лишь типами возвращаемых значений. Они должны отличать-
ся типами или числом параметров. При вызове перегруженного метода выпол-
няется та его версия, параметры которой совпадают (по типу и количеству) с задан-
ными аргументами. Как видите, метод ovlDemo () перегружается четыре раза. Первая версия вообще
не принимает параметров, вторая принимает один целочисленный параметр, третья —
два целочисленных параметра, а четвертая — два double-параметра. Обратите внима-
ние на то, что первые две версии метода ovlDemo () возвращают тип void, т.е. не
возвращают никакого значения, а вторые две возвращают значения соответствующих
типов. Принципиальная значимость перегрузки состоит в том, что она позволяет обра-
щаться к связанным методам посредством одного, общего для всех имени. Следова-
тельно, имя ovlDemo () представляет общее действие, которое выполняется во всех случаях.
Компилятору остается правильно выбрать конкретную версию при конкретных об-
стоятельствах.
12. Статические члены класса: назначение и применение.
Довольно часто при разработке приложений появляется необходимость иметь общие данные для всех объектов одного класса. В этом случае применяют статические данные-члены. Для объявления статических членов класса используется спецификатор static.
Иногда требуется определить член класса, который должен использоваться незави-
симо от объекта этого класса. Обычно к члену класса доступ предоставляется через
объект этого класса. Однако можно создать член, который заведомо разрешено ис-
пользовать сам по себе, т.е. без ссылки на конкретный экземпляр. Чтобы создать та-
кой член, предварите его объявление ключевым словом s t a t i c . Если член объявлен
как s t a t i c , к нему можно получить доступ до создания объектов этого класса и без
ссылки на объект. С использованием ключевого слова s t a t i c можно объявлять как
методы, так и переменные. При использовании static-члена вне класса необходимо указать имя класса и следующий за ним оператор "точка". Объект при этом не нужно создавать. К s t a t i c -
члену получают доступ не через экземпляр класса, а с помощью имени класса. На-
пример, чтобы присвоить число 10 static-переменной с именем count, которая яв-
ляется членом класса Timer, используйте следующую строку кода:
I Timer.count = 10; На static-методы накладывается ряд ограничений.
1. static-метод не имеет ссылки this.
2. static-метод может напрямую вызывать только другие static-методы. Он не
может напрямую вызывать метод экземпляра своего класса. Дело в том, что
методы экземпляров работают с конкретными экземплярами класса, чего не
скажешь о static-методах.
3. static-метод должен получать прямой доступ только к static-данным. Он не
может напрямую использовать переменные экземпляров, поскольку не работа-
ет с экземплярами класса.
13. Константные члены класса: константные свойства, константные методы.
Практически любой объект содержит в себе данные, которые не должны меняться в процессе его использования. Значение их заранее предопределено разработчиком класса или устанавливается один раз в конструкторе при инициализации объекта. Для объявления таких данных в классе используется квалификатор const.Значение атрибутов с таким квалификатором могут быть только проинициализированы, а попытка изменения установленного при инициализации значения вызовет ошибку компиляции. Помимо константных данных класс может содержать константные функции-члены. Константные функции-члены - это такие функции класса, которые не изменяют внутреннее состояние (атрибуты класса) объекта класса. Для их объявления тоже используется квалификатор const , но записывается он в заголовке или прототипе функции после формальных параметров,
Из названия легко догадаться, что константы (constants), представлен-
ные ключевым словом const,— это поля, остающиеся постоянными в тече-
ние всего времени жизни приложения. Определяя что-либо как const, дос-
таточно помнить два правила. Во-первых, константа — это член, значение
которого устанавливается в период компиляции программистом или ком-
пилятором (в последнем случае это значение по умолчанию). Во-вторых,
значение члена-константы должно быть записано в виде литерала.
14. Обработка исключений (try/catch/throw-конструкция).
Исключительная ситуация (или исключение) — это ошибка, которая возникает во
время выполнения программы. Используя С#-подсистему обработки исключи-
тельных ситуаций, с такими ошибками можно справляться. Преимущество подсистемы обработки исключений состоит в автоматизации созда-
ния большей части кода, который ранее необходимо было вводить в программы
"вручную". Например, в любом компьютерном языке при отсутствии такой подсисте-
мы практически каждый метод возвращал коды ошибок, и эти значения проверялись
вручную при каждом вызове метода. Такой подход довольно утомителен, кроме того,
при этом возможно возникновение ошибок. Обработка исключений упрощает "работу
над ошибками", позволяя в программах определять блок кода, именуемый обработчи-
ком исключении, который будет автоматически выполняться при возникновении опре-
деленной ошибки. В этом случае не обязательно проверять результат выполнения ка-
ждой конкретной операции или метода вручную. Если ошибка возникнет, ее долж-
ным образом обработает обработчик исключений. Еще одним преимуществом обработки исключительных ситуаций в С# является
определение стандартных исключений для таких распространенных программных
ошибок, как деление на нуль или попадание вне диапазона определения индекса. Программные инструкции, которые нужно проконтролировать на предмет исклю-
чений, помещаются в try-блок. Если исключение таки возникает в этом блоке, оно
дает знать о себе выбросом определенного рода информации. Это выброшенное исклю-
чение может быть перехвачено программным путем с помощью catch-блока и обрабо-
тано соответствующим образом. Системные исключения автоматически генерируются
С#-системой динамического управления. Чтобы сгенерировать исключение вручную,
используется ключевое слово throw. Любой код, который должен быть обязательно
выполнен при выходе из try-блока, помещается в блок finally. Ядром обработки исключений являются блоки t r y и catch. Эти ключевые слова
работают "в одной связке"; нельзя использовать слово t r y без catch или catch без
try. Вот каков формат записи try/catch-блоков обработки исключений:
t r y {
// Блок кода, подлежащий проверке на наличие ошибок.
}
catch {ExcepTypel exOb) {
// Обработчик для исключения типа ExcepTypel.
}
catch (ExcepType2 exOb) {
// Обработчик для исключения типа ЕхсерТуре2.
}….
Здесь ЕхсерТуре — это тип сгенерированного исключения. Как видно и^ формата записи try/catch-блоков, с try-блоком может быть связана не одна, а несколько catch-инструкций. Перехват одного из стандартных С#-исключений, как показала предыдущая про-
грамма, имеет побочный эффект: он предотвращает аварийное окончание программы.
При генерировании исключения оно должно быть перехвачено программным кодом.
Если программа не перехватывает исключение, оно перехвачивается С#-системой ди-
намического управления. Но дело в том, что система динамического управления со-
общит об ошибке и завершит программу.
Вложенные объекты.
Вложенным объектом будем назвать объект некоторого класса, объявленного в качестве атрибута другого класса.
Вложенные классы.
Вложенным классом называется класс определенный внутри другого класса. Существует два подхода относительно применения таких классов. Некоторые считают, что класс должен быть компонентой максимально изолированной от других классов и применяют вложенные объекты. Другие – допускают применение вложенных классов, если это согласуется с его логикой. Функции-члены вложенных классов обычно размещают в том же файле, что и функции члены внешнего класса
17. Множественное наследование (только для С++).
Определенный ранее класс называется базовым классом, а новый производным. После создания производный класс, в свою очередь, может стать базовым для другого класса. Прямой базовый класс – это базовый класс, из которого совершает явное наследование производный класс. Косвенный базовый класс наследуется из двух или более уровней выше. Если существует несколько уровней наследования, то говорят об иерархии классов. Производный класс, которому добавляется новая функциональность (а значит и новые члены), по размеру больше своего базового класса. Он более специфичен, чем базовый класс и представляет более специализированную группу объектов. Члены производного класса могут использовать открытые (public) и защищенные (protected) члены всех базовых классов. Члены производного класса могут иметь такие же имена, что и члены базовых классов. В этом случае для явного указания используется оператор разрешения области видимости :: (двойное двоеточие) с именем базового класса.
В языке С++ допускается наследование от многих базовых классов. В этом случае говорят множественном наследовании. При множественном наследовании объект производного класса, содержит подобъекты каждого из базовых классов. Перед именем базового класса в заголовке указан модификатор public, указывающий на то, что класс
является открытым базовым классом. Члены производного класса могут использовать открытые (public) и защищенные (protected) члены базового класса. Такое наследование называется открытым наследованием.
Если в заголовке класса перед именем базового класса установлен модификатор protected (защищенный),то это приведет к тому, что все открытые (public) и защищенные (protected)члены базового класса будут доступны только членам производного класса и членам производного от производного класса, но не доступны для прямого вызова из программы, как это было в случае открытого наследования.
В случае закрытого наследования (перед именем базового класса указывается модификатор private)действует такое же правило, что и при защищенном наследовании, но если такой производный класс выступит в качестве базового, то для нового производного класса не будут доступны член косвенного базового класса, даже если новое наследование было отрытым.