Кратко съдържание



страница28/73
Дата21.07.2018
Размер9.03 Mb.
#76887
1   ...   24   25   26   27   28   29   30   31   ...   73

Наследяване


Ще се спрем отново на понятието наследяване поради особената му важност в обектно-ориентираното програмиране. Няма да обясняваме тео­ретичната страна наследяването, тъй като това е извън обхвата на настоящата тема. Ще обясним само как да извършваме наследяване на класове със средствата на езика C#.

В C# синтаксиса и се­ман­тиката на наследяването са близки до тези в други езици за обектно-ори­ентирани езици, като C++ и Java. За да напра­вим даден клас Derived наследник на даден друг клас Base, трябва след декларацията на класа Derived да сложим двоеточие, следвано от името на класа Base. За да илюстрираме това, ще разширим един от примерите, които разгледахме по-горе в темата:



class Student

{

private string mName;



private int mStudentId;

private string mPosition = "Student";

public Student(string aName, int aStudentId)

// ...


public Student(string aName) : this(aName, -1)

// ...
public void PrintName()

{

Console.WriteLine("Student name: {0}", mName);



}

}
public sealed class Kiro : Student

{

public Kiro() : base("Бай Киро", 12345)



{

}
public void Oversleep()

{

//...


}
static void Main()

{

Student tosho = new Student("Тошо", 54321);



Kiro kiro1 = new Kiro();

Student kiro2 = new Kiro();

// Kiro kiro3 = new Student("Бай Киро", 12345); // invalid!

tosho.PrintName();

kiro1.PrintName();

// kiro2.Oversleep();

((Kiro)kiro2).Oversleep();

}

}



Виждаме, че класът Kiro наследява класа Student, с което приема от него всички негови полета, свойства, методи и други членове. Разбира се, наследените членове са достъпни за класа Kiro, само ако не са били обя­вени като private в базовия клас Student.

Трябва да обърнем внимание на третия ред от метода Main(…):



Student kiro2 = new Kiro();

В него създаваме обект от тип Kiro, но го присвояваме на променлива от тип Student. Тази операция е напълно коректна, тъй като при­сво­я­ва­не­то на обект от наследен тип в променлива от базов тип е позволено. Обрат­ното, обаче, не е в сила и ако разкоментираме втория ред, приложението не би се компилирало.

Обръщението kiro1.PrintName() е също напълно валидно, тъй като класът Kiro наследява всички членове на базовия клас Student и затова съдържа дефиницията на метода PrintName().


Класове, които не могат да се наследяват (sealed)


В дефиницията на класа Kiro забелязваме употребата на ключовата дума sealed. С нея указваме, че Kiro не може да бъде наследяван от друг клас. Това е пример как чрез забраняването на наследяване можем да създа­ваме йерархии от класове по-близки до реалните обекти, които предста­вяме. В конкретния пример е удачно да маркираме класа като sealed, тъй като той представ­лява категория, която не може повече да се конкрети­зира (Kiro е клас, който съответства на един конкретен обект от действи­телността, а не на група различни обекти).

Наследяване при структурите


В някои обектно-ориентирани езици, като например C++, се допуска наследяване на структури. В C# и в другите .NET езици това не е позволено.



Структурите в .NET Framework не могат да се наследяват по между си и не могат да наследяват и да бъдат нас­ледявани от класове.

Нека направим един прост експеримент, за да онагледим невъзможността за наследяване на структури. Със следния код ще създадем една три­ви­ал­на структура:

public struct TestStruct

{

}



Отново с помощта на инструмента ildasm получаваме MSIL кода за тази проста структура:

Забелязваме, че структурата TestStruct наследява от System.ValueType и, което в нашия случай е по-интересно, в дефиницията й фигурира моди­фикаторът sealed. Това указва на компилатора, че този тип не може да бъде на­сле­ден. Следната ситуация, при която се опитваме да наследим структура от клас, е също недопустима и предизвиква грешка при опит за компилация:



public class TestClass

{

}


public struct AnotherTestStruct : TestClass

{

}


Конвертиране на обекти


Нека сега разгледаме конвертирането (casting) на обект от даден тип към обект от друг тип. При класове в отношение наследник-наследен можем да конвертираме нагоре по йерархията (upcasting) и надолу по йерархи­ята (downcasting). Нека обясним тези две понятия.

Конвертиране нагоре (upcasting)


С операцията Student kiro2 = new Kiro() от по-горния пример присвоя­ваме обект от клас Kiro на променлива от клас Student, т.е. конверти­раме (преобразуваме) обекта към класа Student. В този случай използ­ваме конвертиране нагоре (up­casting), тъй като Student е базов клас на Kiro или, иначе казано, се намира по-горе в йерархията. Тази опера­ция е напълно допустима, тъй като kiro2 действително е студент.

В нашия пример следващият ред



Kiro kiro3 = new Student("Бай Киро", 12345);

е коментиран, тъй като операцията, която там се опитваме да извършим, е недопустима и този код не би могъл да се компилира, тъй като обектът, който конструираме посредством new Student("Бай Киро", 12345) не е инстанция на класа Kiro (въ­пре­ки че го наподобява по стойностите на полетата, той не съдържа метода Oversleep()).

Конвертиране надолу (downcasting)


С обръщението (Kiro)kiro2 разглеждаме обекта kiro2 като обект от тип Kiro. Тази операция наричаме конвертиране надолу, или down­casting. Типът на израза в скобите е Kiro и заради това можем свободно да извикаме метода Oversleep(), защото въпреки, че е сочен от променлива от тип Student, този израз фактически е инстанция на класа Kiro и съдържа им­пле­мен­та­ция на метода. На долната илюстрация виждаме, че и Visual Studio .NET разпознава типа на израза като ни предоставя члено­вете му в па­да­щото меню за автоматично завършване на израза:





В C# конвертирането надолу е синтактично валидна опера­ция, независимо дали обектът, който конвертираме, е дей­ствително от въпросния наследяващ типа. Например, за­коментираното обръщение Kiro kiro3 = new Student("Бай Киро", 12345) би мог­ло да се зададе във вида Kiro kiro3 = (Kiro)new Student("Бай Киро", 12345), което се компилира успешно от C# ком­пи­ла­тора без дори да генерира преду­преждение, тъй като по време на ком­пилация не е извест­но дали типовете са съвместими. При из­пълнението на този код, обаче, въпросното преобразуваме ще предизвика из­ключение System.InvalidCastException, тъй като конструи­раният обект не е от тип Kiro или съвместим с него тип.



Сподели с приятели:
1   ...   24   25   26   27   28   29   30   31   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница