Public override void AbstractMethod()



   {

       _x++;

       _y++;

   }

   public override int X // overriding property

   {

Get

       {

           return _x + 10;

       }

   }

   public override int Y // overriding property

   {

Get

       {

           return _y + 10;

       }

   }

Static void Main()

   {

       DerivedClass o = new DerivedClass();

       o.AbstractMethod();

       Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);

   }

15
Механизм наследования позволяет расширить или создавать конкретные классы от одного более общего класса.
При порождении от базового класса важным становится вопрос о доступности этих членов. Приватные члены базового класса не доступны из дочернего класса, а общедоступные – доступны. хотелось бы иметь такие члены класса, которые доступны из базового, дочернего классов, но не из внешнего класса. Такой уровень доступности называется protected. Помимо уровня защиты членов класса в производном классе можно определить способ наследования. Члены базового класса могут быть виртуальными, это значит что в производном классе может содержаться альтернативная реализация virtual члена. Эта альтернативная реализация не отменяет исходной реализации, но делает ее недоступной извне. При отсутствии

альтернативной реализации любой внешний код обращается к коду этого члена в базовом классе.

 

16

Перегрузка операций

В класс Animals можно добавить новое свойство Weight. Перегрузка операций позволяет предоставить логику неявного использования свойства Weight, чтобы можно было упростить пример (1) и получить (2):

1)if (cowA.Weight>cowB.Weight)

{

}

2)if (cowA>cowB)

{

}

В примере операция «больше» перегружена. Перегруженной так же называется операция, для которой написан выполняющий её код. Этот код добавляется в определение одного из классов, для экземпляров которого должна выполняться перегрузка операции. Аналогично можно добавлять перегрузку операций для работы с разными классами. Перегрузка возможна только для операций, существующих в языке C#; новые операции создавать нельзя.

 

Наследование от общего предка:

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

 

Необязательные аргументы

В определении метода, конструктора, индексатора или делегата можно указать, что параметры являются обязательными или необязательными.При каждом вызове необходимо указывать аргументы для всех обязательных параметров, но можно опустить аргументы для необязательных параметров.

В рамках определения каждого необязательного параметра задается его значение по умолчанию.Если для параметра не передается аргумент, используется значение по умолчанию.Значения по умолчанию должны быть константами.

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



C#


public void ExampleMethod(int required, string optionalstr = "default string",

int optionalint = 10)

 

Следующий вызов ExampleMethod вызывает ошибку компилятора, поскольку аргумент предоставлен для третьего параметра, а не для второго.

//anExample.ExampleMethod(3, ,4);

Но если имя третьего параметра известно, задачу можно выполнить с использованием именованного аргумента.

anExample.ExampleMethod(3, optionalint: 4);

IntelliSense использует квадратные скобки для указания необязательных параметров.

 

17

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

Метод объявляется как виртуальный в базовом классе с помощью ключевого слова virtual, указываемого перед его именем. Когда же виртуальный метод переопределяется в производном классе, то для этого используется модификатор override. А сам процесс повторного определения виртуального метода в производном классе называется переопределением метода. При переопределении имя, возвращаемый тип и сигнатура переопределяющего метода должны быть точно такими же, как и у того виртуального метода, который переопределяется. Кроме того, виртуальный метод не может быть объявлен как static или abstract.

Если при наличии многоуровневой иерархии виртуальный метод не переопределяется в производном классе, то выполняется ближайший его вариант, обнаруживаемый вверх по иерархии.

Пример:

// Создаем виртуальный метод

   public virtual string FontInfo(Font obj)

   {

       string s = "Информация о шрифте: \n------------------\n\n" +

           "Тип шрифта: " + typeFont +

           "\nРазмер шрифта: " + fontSize + "\n";

       return s;

   }

}

// Производный класс 1 уровня

class ColorFont : Font

{

   byte Color;

   public ColorFont(byte Color, string TypeFont, short FontSize)

       : base(TypeFont, FontSize)

   {

       this.Color = Color;

   }

   // Переопределение для виртуального метода

   public override string FontInfo(Font obj)

   {

       // Используется ссылка на метод определенный в базовом классе Font

       return base.FontInfo(obj) + "Цвет шрифта: " + Color + "\n";

   }

 

   // Создадим виртуальное свойство

   public virtual byte color

   {

       set

       {

           Color = value;

       }

       get

       {

           return Color;

       }

   }

}

18

Интерфейс представляет собой полностью абстрактный класс, все методы которого абстрактны.

От абстрактного класса интерфейс отличается некоторыми деталями в синтаксисе и поведении:

● синтаксическое отличие состоит в том, что методы интерфейса объявляются без указания модификатора доступа

● отличие в поведении заключается в более жестких требованиях к потомкам.

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

Опишем некоторый интерфейс, задающий дополнительные свойства объектов класса:

public interface IProps

{

void Prop1(string s);

void Prop2 (string name, int val);

}

У этого интерфейса два метода, которые и должны будут реализовать все классы -наследники интерфейса.

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

 Вот пример:

public class Clain:IProps

{

public Clain() {}

public void Prop1(string s)

{

Console.WriteLine(s);

}

public void Prop2(string name, int val)

{

Console.WriteLine("name = {0}, val ={1}", name, val);

}

}//Clain - Класс реализует наследников.

 

 

19

Наследование интерфейсов

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

Тем не менее, одна коллизия при множественном наследовании интерфейсов и при реализации нескольких интерфейсов одним классом всё-таки возможна. Она возникает, когда в двух или более интерфейсах, наследуемых новым интерфейсом или реализуемых классом, имеются методы с одинаковыми сигнатурами. Разработчики языков программирования вынуждены выбирать для таких случаев те или иные способы разрешения противоречий. Вариантов здесь несколько: запрет на реализацию, явное указание конкретного и реализация базового интерфейса или класса.

· Запрет. В одном классе просто запрещается реализовывать несколько интерфейсов, имеющих методы с одинаковыми сигнатурами. Если для какого-то класса требуется комбинация несовместимых интерфейсов, программист должен выбрать другой путь решения проблемы, например, выделить несколько классов, каждый из которых реализует один из необходимых интерфейсов, и использовать их экземпляры совместно.

· Явное разрешение неоднозначности. В случае обнаружения компилятором коллизии от программиста требуется явно указать, метод какого из интерфейсов он реализует и вызывает. То есть одноимённые методы реализуются раздельно, а при вызове указывается, какой из них вызывается. При вызове одноимённых методов через переменную типа «интерфейс» неоднозначность не возникает, если использованный в качестве типа переменной интерфейс имеет только один метод с заданным именем. Вариантом этого решения является явное переименование для совпадающих по именам наследуемых или реализуемых методов, за счёт чего в пределах реализующего класса нет одноимённых методов, но при обращении через интерфейс всегда вызывается нужная реализация.

· Общая реализация одноимённых методов. Если наследуется или реализуется несколько методов с одной и той же сигнатурой, то они объединяются в интерфейсе-наследнике, а в классе-реализаторе получают одну общую реализацию. Это хорошо подходит для случаев, когда одноимённые методы разных интерфейсов идентичны по предполагаемой функциональности, но может вызвать нежелательные эффекты, если поведение этих методов должно различаться.

 В C# интерфейсы могут наследовать один или несколько других интерфейсов. Членами интерфейсов могут быть методы, свойства, события и индексаторы.

пример наследования интерфейсов:

public interface IParent

{

void ParentMethod();

}

public interface ISon1:IParent

{

void Son1Method();

}

public interface ISon2:IParent

{

void Son2Method();

Рассмотрим две основные проблемы:

1) коллизию имен;

2) наследование от общего предка.

Коллизия имен-Проблема коллизии имен возникает, когда два или более интерфейса имеют

методы с одинаковыми именами и сигнатурой (то есть типы и количество их аргументов

совпадает).

Если имена методов совпадают, но сигнатуры разные, то это не приводит к

конфликтам .

решение проблемы:

1) склеивание методов

2) переименование.

Пример двух интерфейсов, имеющих методы с одинаковой сигнатурой, и класса -

наследника этих интерфейсов, применяющего разные стратегии реализации для

конфликтующих методов.

public interface IProps

{

void Prop1(string s);

void Prop2 (string name, int val);

void Prop3();

}

public interface IPropsOne

{

void Prop1(string s);

void Prop2 (int val);

void Prop3();

}

Здесь у двух интерфейсов - по три метода с совпадающими именами, сигнатуры

двух методов совпадают, а в одном случае различаются.


Дата добавления: 2018-05-12; просмотров: 401; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!