русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Інтерфейси і спадкоємство


Дата додавання: 2015-01-08; переглядів: 1030.


Інтерфейс може не мати або мати скільки завгодно інтерфейсів-предків, в останньому випадку він успадковує всі елементи всіх своїх базових інтерфейсів, починаючи з самого верхнього рівня. Базові інтерфейси мають бути доступні як і їх нащадки. Як і в звичайній ієрархії класів, базові інтерфейси визначають загальну поведінку, а їх нащадки конкретизують і доповнюють його. У інтерфейсі-нащадку можна також вказати елементи, які змінюють успадковані елементи з такою ж сигнатурою. В цьому випадку перед елементом указується ключове слово new, як і в аналогічній ситуації в класах. За допомогою цього слова відповідний елемент базового інтерфейсу приховується. Приклад:

interface IBase

{

void F(int i );

}

interface Ileft : IBase

{

new void F( int i ); // перевизначення методу F

{

 

interface Iright : IBase

{

void G();

}

interface IDerived : ILeft, IRight {}

 

class A

{

void Test( IDerived d ) {

d.F(1); // Викликається ILeft.F

((IBase)d). F(1): // Викликається IBase.F

((ILeft )d). F(1); //' Викликається ILeft. F

((IRight)d).F(1); // Викликається IBase.F

}

}

 

Метод F з інтерфейсу IBase прихований інтерфейсом ILeft, не дивлячись на те що в ланцюжку IDerived - IRight - IBase він не перевизначався.

Клас, що реалізовує інтерфейс, повинен визначати всі його елементи, зокрема успадковані. Якщо при цьому явно указується ім'я інтерфейсу, воно повинне посилатися на той інтерфейс, в якому був описаний відповідний елемент, наприклад:

 

class А : IRight

{

IRight.G() { ... }

IBase.F( int i ) { ... } // IRight.F( int i ) - не можна

}

Інтерфейс, на власні або успадковані елементи якого є явне посилання, має бути вказаний в списку предків класу, наприклад:

class В : А

{

// IRight.G() { ... } не можна!

}

 

class С : A, IRight

{

IRight.G() { ... } // можна

IBase.F( int i ) { ... } // можна

}

 

Клас успадковує всі методи свого предка, зокрема ті, які реалізовували інтерфейси. Він може перевизначити ці методи за допомогою специфікатора new, але звертатися до них можна буде тільки через об'єкт класу. Якщо використовувати для звернення посилання на інтерфейс, викликається не перевизначена версія:

interface IBase

{

void А();

}

 

class Base : IBase

{

public void A() { ... }

}

class Derived: Base

{

new public void A() { ... }

}

...

Derived d = new Derived ();

d.A(); // викликається Derived.A();

IBase id = d;

id.A(); // викликається Base.A();

 

Проте якщо інтерфейс реалізується за допомогою віртуального методу класу, після його перевизначення в нащадку будь-який варіант звернення (через клас або через інтерфейс) приведе до одного і того ж результату:

 

interface IBase

{

void А();

}

class Base : IBase

{

public virtual void A() { ... }

}

class Derived: Base

{

Public override void A() { ... }

}

...

Derived d = new Derived ();

d.A(); // викликається Derived.A();

IBase id = d;

id.A(); // викликається Base.A();

 

Метод інтерфейсу, реалізований явною вказівкою імені, оголошувати віртуальним забороняється. При необхідності перевизначити в нащадках його поведінку користуються наступним прийомом: з цього методу викликається інший, захищений метод, який оголошується віртуальним. У приведеному далі прикладі метод А інтерфейсу IВase реалізується за допомогою захищеного віртуального методу А, який можна перевизначати в нащадках класу Base:

 

interface IBase

{

void A();

}

 

class Base : IBase

{

void IBase.A() { A_(); }

protected virtual void A_() { ... }

}

 

class Derived: Base

{

protected override void A() { ... }

}

 

Існує можливість повторно реалізувати інтерфейс, вказавши його ім'я в списку предків класу разом з класом-предком, що вже реалізував цей інтерфейс. При цьому реалізація перевизначених методів базового класу до уваги не береться:

 

interface IBase

{

void А();

}

 

class Base : IBase

{

void IBase.A() { ... } // не використовується в Derived

}

 

class Derived : Base, IBase

{

public void A() { ... }

}

 

Якщо клас успадковує від класу і інтерфейсу, які містять методи з однаковими сигнатурами, успадкований метод класу сприймається як реалізація інтерфейсу, наприклад:

 

interface Interfacel

{

void F( ):

}

 

class Class1

{

public void F() { ... }

public void G{} { ... }

}

 

class Class2 : Class1, Interface1

{

new public void G( ) { ... }

}

 

Тут клас Class2 успадковує від класу Class1 метод F. Інтерфейс Interface1 також містить метод F. Компілятор не видає помилку, тому що клас Class2 містить метод, відповідний для реалізації інтерфейсу.

Взагалі при реалізації інтерфейсу враховується наявність “відповідних” методів в класі незалежно від їх походження. Це можуть бути методи (описані в поточному або базовому класі) які реалізують інтерфейс явним або неявним чином.

 


<== попередня лекція | наступна лекція ==>
Реалізація інтерфейсу | Перевантаження операцій відношення


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн