Смекни!
smekni.com

Основы алгоритмизации и программирования 2 (стр. 23 из 32)

Помимо указания базовых классов, мы можем таким же способом – через двоеточие – указать и поддерживаемые интерфейсы. Если одновременно требуется задавать базовый класс, то он должен располагаться первым после двоеточия, а интерфейсы – за ним. Если базовый класс не задается, то интерфейсы указываются непосредственно за двоеточием. Для отделения имени базового класса (если таковое присутствует) и для отделения одних имен интерфейсов от других следует использовать запятую.

Например, мы можем добавить в класс MyClass интерфейс:

public class MyClass : IMyInterface { // члены класса }

Все члены, являющиеся интерфейсами, должны иметь реализацию в любом классе, поддерживающем данный интерфейс, хотя, конечно, всегда существует возможность реализовать "пустой" интерфейс (без какого бы то ни было функционального кода), если от данного члена не требуется выполнения каких-либо действий.

Следующее объявление неверно, поскольку базовый класс MyBase не является первым вхождением списка наследования:

public class MyClass: IMyInterface, MyBase {

// члены класса }

Правильный способ задать и базовый класс, и интерфейс следующий:

public class MyClass : MyBase, IMyInterface { // члены класса }

Не забывайте, что допускается наличие нескольких интерфейсов, поэтому следующий код также является допустимым:

public class МуСlass: MyBase, IMyInterface, IMySecondInterface { // члены класса }

Ниже приводится таблица допустимых в определениях классов комбинаций модификаторов доступа.

Модификатор

Значение

Отсутствует internal

либо

Класс доступен только в рамках текущего проекта

public

Класс доступен отовсюду

abstract или

abstract

internal

Класс доступен только в рамках текущего проекта, не допускает создания экземпляров, может только наследоваться

publicabstract

Класс доступен отовсюду, не допускает создания экземпляров, может только наследоваться

sealedилиinternalsealed

Класс доступен только в рамках текущего проекта, не может наследоваться, допускает только создание экземпляров

publicsealed

Класс доступен отовсюду, не может наследоваться, допускает только создание экземпляров

System.Object

Поскольку все классы наследуются от System.Object, то они обладают доступом ко всем его защищенным и общим членам. Поэтому имеет смысл ознакомиться с тем, что нам доступно System.Object содержит следующие методы:

Метод

Возвращаемый тип

Виртуальн ый

Статиче -ский

Описание

Object()

Отсутствует

Нет

Нет

Конструктор типаSystem.Object.Автоматически вызывается конструкторамипроизводных типов

-Object() (также известен под именем

Finalize())

Отсутствует

Нет

Нет

Деструктор для типаSystem.ObjectАвтоматически вызывается деструкторамипроизводных типов, сам по себе вызванбыть не может

Equals (object)

bool

Да

Нет

Сравнивает объект, для котороговызывается, с другим объектом и возвращает значение true, если они равны. Реализация, выполняющаяся по умолчанию, проверяет, ссылается ли переданный в качестве параметра объект на тот же самый объект (поскольку объекты представляют собой ссылочные типы). Если необходимо сравнивать объекты каким-либо иным образом, например, на предмет одинакового значения, этот метод может быть переопределен.

Equals (object, object)

bool

Нет

Да

Сравнивает два объекта, передаваемых ему в качестве параметров, на предмет того, равны ли они. Эта проверка выполняется. С помощью метода Equals (object). Заметьте, что, если оба объекта обладают нулевыми ссылками, возвращается значениеtrue.

ReferenceEq uals(object, object)

bool

Нет

Да

Сравнивает два переданных ему объекта, определяя, являются ли они ссылками на один и тот же экземпляр.

ToString()

string

Да

Нет

Возвращает строку, соответствующую экземпляру объекта. По умолчанию это квалифицированное имя класса (см предыдущий пример), однако метод можно переопределить для выполнения действий, подходящих для типа данного класса.

Memberwise Clone()

object

Нет

Нет

Копирует объект посредством создания нового экземпляра объекта и копирования всех членов. Обратите внимание, что такое копирование членов не приводит к созданию новых экземпляров этих членов. Любые члены ссылочного типа в новом объекте будут ссылаться на те же объекты, на которые они ссылаются в исходном классе. Рассматриваемый метод является защищенным, поэтому его можно использовать внутри класса или внутри производных классов.

GetType()

System.Type

Нет

Нет

Возвращает тип объекта в виде объектаSystem.Type.

GetHashCod

e()

int

Да

Нет

Используется как функция хеширования для объектов. Хеш-функция – это функция, возвращающая значение, которое позволяет идентифицировать объект в некоторой сжатой форме.

Эти методы являются основными, они должны поддерживаться всеми типами обектов в .NET Framework, хотя, возможно, некоторые из них вам никогда не придется использовать (или только в определенных обстоятельствах, как, например, GetHashCode()).

Метод GetType () полезен при использовании полиморфизма, поскольку он позволяет выполнять разные коды для объектов разных типов, а не один и тот же код для всех объектов, как это часто бывает. Например, если у нас имеется функция, которой передается параметр типа object (это означает, что мы можем передавать ей практически все, что угодно), то можно предусмотреть выполнение в ней специальных работ в случае поступления объектов конкретного типа. Воспользовавшись сочетанием Getrype() с typeof() (оператор С#, который преобразовывает имя класса в объект System.Type), мы получаем возможность выполнять сравнения примерно следующим образом:

if (typeof(myObj) = = typeof(MyComplexClass)) {

// Объект myObj является экземпляром класса MyComplexClass }

Возвращаемый объект system.туре обладает гораздо более широкими возможностями, но здесь мы не будем на нем останавливаться.

Очень часто оказывается весьма полезным переопределить метод ToString (), особенно в тех ситуациях, когда содержимое объекта может быть с легкостью представлено в виде одной удобочитаемой строки.

6.2.Конструкторы и деструкторы

Когда мы описываем какой-либо класс в С#, то в большинстве случаев нет необходимости описывать соответствующие ему конструкторы и деструкторы, поскольку объект базового класса System.Object обеспечивает их реализацию по умолчанию. Однако иногда стоит описать их самостоятельно, что позволит инициализировать и уничтожать объекты.

Для того чтобы добавить в класс простой конструктор, необходимо воспользоваться следующим несложным синтаксисом:

class MyClass { public MyClass()

{

// Код конструктора }}

Такой конструктор обладает тем же именем, что и класс, в котором он содержится, не имеет параметров (что превращает его в конструктор, использующийся по умолчанию) и является общим, что позволяет создавать экземпляры объектов данного класса (более подробная информация по этому вопросу содержится в предыдущей лекции).

Существует также возможность использовать частный конструктор по умолчанию, что означает, что экземпляры объектов данного класса не могут создаваться с помощью этого конструктора (еще раз отсылаем читателей к предыдущей лекции).

class MyClass { private MyClass()

{

// Код конструктора

}

}

Кроме того, у нас имеется возможность аналогичным образом определить конструкторы данного класса, использующиеся не по умолчанию; для этого достаточно просто задать параметры. Например:

class MyClass

{

public MyClass () {

// Код конструктора, использующегося по умолчанию } public MyClass (int myInt) {

// Код конструктора, использующегося не по

// умолчанию (используется параметр myInt) } } Количество задаваемых конструкторов не ограничено.

Деструкторы определяются с помощью несколько иного синтаксиса. Деструктор, используемый в .NET (и предоставляемый классом System.Object), называется Finalize(), однако для объявления деструктора используется другое имя. Вместо того чтобы переопределять Finalize(), мы используем следующий код:

class MyClass {

~MyClass()

{

// тело деструктора } }

Код, заключенный в деструкторе, будет выполняться при сборке мусора, позволяя освобождать удерживаемые ресурсы. После вызова деструктора происходят явные вызовы деструкторов базовых классов, включая вызов Finalize() в корневом классе System.Object. Такой способ позволяет .NET Framework гарантировать выполнение, поскольку переопределение Finaiize() означало бы, что необходимы явные вызовы базовых классов, а это таит в себе потенциальную опасность (мы познакомимся с вызовом методов базовых классов в следующей лекции).