Сокрытие имен. Операторы this и base.




Инкапсуляция. Понятие, пример.

Инкапсуляция – это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя.

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

Код и данные, составляющие вместе класс, называют членами. Данные, определяемые классом, называют полями, или переменными экземпляра. А код, оперирующий данными, содержится в функциях-членах, самым типичным представителем которых является метод. В C# метод служит в качестве аналога подпрограммы. (К числу других функций-членов относятся свойства, события и конструкторы.) Таким образом, методы класса содержат код, воздействующий на поля, определяемые этим классом.

publicclass A

{

publicint a; // открытыйинтерфейс

publicint b; // открытыйинтерфейс

publicintReturnSomething(); // открытыйинтерфейс

privateintAa= a; //безопасное использование открытого интерфейса

privateintAb= b; //безопасное использование открытого интерфейса

privatevoidDoSomething(); // скрытыйметод.

};


3. Полиморфизм

Полиморфизм, что по-гречески означает “множество форм”, — это свойство, позволяющее одному интерфейсу получать доступ к общему классу действий. Простым примером полиморфизма может служить руль автомашины, который выполняет одни и те же функции своеобразного интерфейса независимо от вида применяемого механизма управления автомашиной. Это означает, что руль действует одинаково независимо от вида рулевого управления: прямого действия, с усилением или реечной передачей. Следовательно, при вращении руля влево автомашина всегда поворачивает влево, какой бы вид управления в ней ни применялся. Главное преимущество единообразного интерфейса заключается в том, что, зная, как обращаться с рулем, вы сумеете водить автомашину любого типа


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

Абстрактныеклассы. Пример.

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

Кроме обычных методов абстрактный класс может иметь абстрактные методы. Подобные методы определяются с помощью ключевого слова abstract и не имеют никакого функционала:

  publicabstractvoidDisplay();

При этом производный класс обязан переопределить и реализовать все абстрактные методы и свойства, которые имеются в базовом абстрактном классе. При переопределении в производном классе такой метод также объявляется с модификатором override. Также следует учесть, что если класс имеет хотя бы одно абстрактное свойство или метод, то он должен быть определен как абстрактный.
namespaceConsoleApplication1

{

// Создаемабстрактныйкласс

AbstractclassUserInfo

{

protectedstring Name;

protectedbyte Age;

 

publicUserInfo (string Name, byte Age)

{

this. Name = Name;

this. Age = Age;

}

 

// Абстрактныйметод

publicabstractstringui ();

}

 

classUserFamily: UserInfo

{

string Family;

 

publicUserFamily (string Family, string Name, byte Age): base (Name, Age)

{

this. Family = Family;

}

 

// Переопределяемметодui

publicoverridestringui ()

{

return Family + " " + Name + " " + Age;

}

}

 

ClassProgram

{

staticvoidMain (string [] args)

{

UserFamily user1 = new UserFamily("Erohin", "Alexandr", 26);

Console.WriteLine(user1.ui());

 

Console.ReadLine();

}

}

}

Виртуальный член класса

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

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

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

classTestClass

{

publicclass Shape

{

publicconstdouble PI = Math.PI;

protecteddouble x, y;

public Shape()

{

}

public Shape(double x, double y)

{

this.x = x;

this.y = y;

}

 

publicvirtualdouble Area()

{

return x * y;

}

}

 

publicclass Circle: Shape

{

public Circle(double r): base(r, 0)

{

}

 

publicoverridedouble Area()

{

return PI * x * x;

}

}

 

class Sphere: Shape

{

public Sphere(double r): base(r, 0)

{

}

 

publicoverridedouble Area()

{

return 4 * PI * x * x;

}

}

 

class Cylinder: Shape

{

public Cylinder(double r, double h): base(r, h)

{

}

 

publicoverridedouble Area()

{

return 2 * PI * x * x + 2 * PI * x * y;

}

}

 

staticvoid Main()

{

double r = 3.0, h = 5.0;

Shape c = new Circle(r);

Shape s = new Sphere(r);

Shape l = new Cylinder(r, h);

// Display results:

Console.WriteLine("Area of Circle = {0:F2}", c.Area());

Console.WriteLine("Area of Sphere = {0:F2}", s.Area());

Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());

}

}

Перегрузка методов

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

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

Совершенно недостаточно, чтобы два метода отличались только типами возвращаемых значений. Они должны также отличаться типами или числом своих параметров. (Во всяком случае, типы возвращаемых значений дают недостаточно сведений компилятору C#, чтобы решить, какой именно метод следует использовать.) Разумеется, перегружаемые методы могут отличаться и типами возвращаемых значений. Когда вызывается перегружаемый метод, то выполняется тот его вариант, параметры которого соответствуют (по типу и числу) передаваемым аргументам.

ClassUserInfo

{

// Перегружаем метод ui

publicvoidui ()

{

Console.WriteLine("Пустойметод\n");

}

 

publicvoidui (string Name)

{

Console.WriteLine("Имяпользователя: {0}",Name);

}

 

publicvoidui (string Name, string Family)

{

Console.WriteLine("Имяпользователя: {0}\nФамилияпользователя: {1}",Name,Family);

}

 

publicvoidui (string Name, string Family, byte Age)

{

Console.WriteLine("Имяпользователя: {0}\nФамилияпользователя: {1}\nВозраст: {2}", Name, Family, Age);

}

}

 

ClassProgram

{

staticvoidMain (string [] args)

{

UserInfo user1 = new UserInfo();

// Разные реализации вызова перегружаемого метода

user1.ui();

user1.ui("Ерохин", "Александр", 26);

 

Console.ReadLine();

}

}

}

 

 

Интерфейс

 

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

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

Для реализации интерфейса в классе должны быть предоставлены тела (т.е. конкретные реализации) методов, описанных в этом интерфейсе. Каждому классу предоставляется полная свобода для определения деталей своей собственной реализации интерфейса. Следовательно, один и тот же интерфейс может быть реализован в двух классах по-разному. Тем не менее в каждом из них должен поддерживаться один и тот же набор методов данного интерфейса. А в том коде, где известен такой интерфейс, могут использоваться объекты любого из этих двух классов, поскольку интерфейс для всех этих объектов остается одинаковым. Благодаря поддержке интерфейсов в C# может быть в полной мере реализован главный принцип полиморфизма: один интерфейс — множество методов.

Интерфейсы объявляются с помощью ключевого слова interface. Ниже приведена упрощенная форма объявления интерфейса:

interface имя{

возвращаемый_тип имя_метода_1 (список_параметров);

возвращаемый_тип имя_метода_2 (список_параметров);

//...

возвращаемый_типимя_метода_N (список_параметров);

}

 

 

interfaceIMan
{
string Name
{
get;
set;
}

}

public class People: IMan
{

private string name;
public string Name
{
get {return name; }
set {name = value; }
}

public People()
{name = «no name»;}
}

Головнаяпрограмма:

People e1 = new People();
e1.Name = “ИвановИван;”
System.Console.WriteLine(«People name: {0}», e1.Name);

Модификаторы доступа

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

В C# применяются следующие модификаторы доступа:

· public: публичный, общедоступный класс или член класса. Такой член класса доступен из любого места в коде, а также из других программ и сборок.

· private: закрытый класс или член класса. Представляет полную противоположность модификатору public. Такой закрытый класс или член класса доступен только из кода в том же классе или контексте.

· protected: такой член класса доступен из любого места в текущем классе или в производных классах.

· internal: класс и члены класса с подобным модификатором доступны из любого места кода в той же сборке, однако он недоступен для других программ и сборок (как в случае с модификатором public).

· protectedinternal: совмещает функционал двух модификаторов. Классы и члены класса с таким модификатором доступны из текущей сборки и из производных классов.

 

· int a; // всеравно, что private int a;

· privateint b; // поле доступно только из текущего класса

· protectedint c; // доступно из текущего класса и производных классов

· internalint d; // доступно в любом месте программы

· protectedinternalint e; // доступно в любом месте программы и из классов-наследников

· publicint f; // доступно в любом месте программы, а также для других программ и сборок

·

· privatevoidDisplay_f()

· {

· Console.WriteLine("Переменная f = {0}", f);

· }

·

· publicvoidDisplay_a()

· {

· Console.WriteLine("Переменная a = {0}", a);

· }

·

· internalvoidDisplay_b()

· {

· Console.WriteLine("Переменная b = {0}", b);

· }

·

· protectedvoidDisplay_e()

· {

· Console.WriteLine("Переменная e = {0}", e);

· }

· }

 

Сокрытие имен. Операторы this и base.

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

ClassMyClass

{

publicchar ch;

 

// 2 метода использующие входной параметр ch, при

// этом во втором методе используется ключевое слово this

publicvoidMethod1 (char ch)

{

ch = ch;

}

 

publicvoidMethod2 (char ch)

{

this. ch = ch;

}

}

 

ClassProgram

{

staticvoidMain ()

{

char myCH = 'A';

Console.WriteLine("Исходныйсимвол {0}",myCH);

 

MyClassobj = new MyClass();

 

obj.Method1(myCH);

Console.WriteLine("Использование метода без ключевого слова this: {0}", obj.ch);

obj.Method2(myCH);

Console.WriteLine("Использование метода c ключевым словом this: {0}", obj.ch);

Console.ReadLine();

}

}

 

Ключевое слово base используется для доступа к членам базового класса из производного класса:

· Вызов метода базового класса, который был переопределен другим методом.

· Определение конструктора базового класса, который должен вызываться при создании экземпляров производного класса.

Доступ к базовому классу разрешен только в конструкторе, методе экземпляра или методе доступа экземпляра.

Использование ключевого слова base в статическом методе является недопустимым.

Базовый класс, к которому осуществляется доступ, является базовым классом, заданным в объявлении класса. Например, если указать classClassB:ClassA, члены ClassA будут доступны из ClassB, независимо от базового класса ClassA

publicclass Person

{

protectedstringssn = "444-55-6666";

protectedstring name = "John L. Malgraine";

 

publicvirtualvoidGetInfo()

{

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

Console.WriteLine("SSN: {0}", ssn);

}

}

class Employee: Person

{

publicstring id = "ABC567EFG";

publicoverridevoidGetInfo()

{

// Calling the base class GetInfo method:

base.GetInfo();

Console.WriteLine("Employee ID: {0}", id);

}

}

 

classTestClass

{

staticvoid Main()

{

Employee E = newEmployee();

E.GetInfo();

}

}

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

// Пример сокрытия имени с наследственной связью.

usingSystem;

class А {
publicint i = 0;
}

// Создать производный класс.
class В: А {
newint i; // этот член скрывает член i из класса А
public В(int b) {
i = b; // член i в классе В
}

publicvoidShow() {
Console.WriteLine("Член i в производном классе: " + i);
}
}

classNameHiding {
staticvoidMain() {
В ob = new В(2);

ob. Show ();
}
}

Прежде всего обратите внимание на использование ключевого слова new в следующей строке кода:

newint i; // этот член скрывает член i из класса А

В этой строке, по существу, компилятору сообщается о том, что вновь создаваемая переменная i намеренно скрывает переменную i из базового класса А и что автору программы об этом известно. Если же опустить ключевое слово new в этой строке кода, то компилятор выдаст предупреждающее сообщение.
Вот к какому результату приводит выполнение приведенного выше кода:

Член i в производном классе: 2

В классе В определяется собственная переменная экземпляра i, которая скрывает переменную i из базового класса А. Поэтому при вызове метода Show () для объекта типа В выводится значение переменной i, определенной в классе В, а не той, что определена в классе А.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-12-07 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: