Язык программирования считается объектно-ориентированным, если в нем реализованы механизм классов и объектов, а также три важных свойства
(я их считаю возможностями):
- Инкапсуляция - это возможность скрыть некоторые члены класса от пользователя. Например, предотвратить вмешательство пользователя во внутреннюю структуру класса, предотвратить ошибки, которые могут возникнуть в результате изменений пользователя и т.д.
- Наследование - это возможность создания производных классов на основе базовых классов, которые также называют классами-предками. Существуют такие классы, объекты которых не могут быть созданы, т.к. эти классы необходимо доопределить. Такие классы называются абстрактными и могут быть только предками, причем, в производном классе должны быть определены тела
(код) методов, являющихся абстрактными (т.е. только прототип) в базовом классе. Методы, определенные виртуальными в базовом классе, могут быть переопределены. Метод, определенный абстрактным, автоматически становится виртуальным. Абстрактный класс может отражать некоторые общие свойства и методы для разных типов объектов, его можно назвать интерфейсом; но в С# принято называть интерфейсами немного другое
- интерфейс содержит только прототипы методов без тел и не содержит переменных-членов. Другими словами, интерфейс определяет, что делать, но не определяет, как делать. Интерфейс также может быть унаследован производным классом. Абстрактные классы и интерфейсы несут некоторую фундаментальную неполную информацию об объекте. - Полиморфизм - это возможность одинакового обращения к методам объектов разного типа. Использование одного интерфейса в качестве предка для нескольких классов порождает полиморфизм.
Инкапсуляция в С# достигается за счет применения модификаторов доступа public, private & protected, internal. Как в С++, не так ли? Да, но...
В С++ мы писали так:
private:
закрытые члены;//не доступны клиенту
protected:
защищенные от клиента, но доступные производному классу члены;
public:
открытые члены;//доступны клиенту
А в C# вот как:
private член1;
public член2;
protected член3;
.....
Т.е. уровень доступа указывается явно для каждого члена. Если это функции
(методы), то перед именем указывается тип возвращаемого значения, после имени в круглых скобках указывается список аргументов, перед типом может стоять некоторое ключевое слово.
Модификатор internal - нечто среднее между public и protected, в зависимости от того, где находится код. Это достаточно специфичный модификатор доступа. Член становится видимым только в пределах текущей единицы компиляции. Я считаю, что в написании прог им можно не пользоваться, но его знание может пригодиться в анализе других прог. Хотя, я намереваюсь все же его затронуть в своих статьях.
Об инкапсуляции все самое основное вы должны были понять, остальное
это вопрос энтузиазма.
Наследование реализуется довольно просто.
Приведем пример:
using sc=System.Console;
class Stone //это будет базовый класс
{
protected float weight;//использован модификатор
protected int color;//protected в целях наследования.
public Stone(){weight=0;color=0;}//конструктор
public Stone(float w,int c) //конструктор с параметрами
{
weight=w;//присваивание значений
color=c;
}
public void Print() //метод вывода
{
sc.WriteLine("The weight is "+weight);
sc.WriteLine("The color number is "+color);
sc.ReadLine();
}
}
class Diamond:Stone //это производный класс
{
private double price;//не доступно вне класса
public Diamond(){price=0;}
public Diamond(float ww,int cc,double pp):base(ww,cc)
{price=pp;}//вызов конструктора базового класса и дополнение его своим опреациями
new public void Print() //метод вывода.
//new скрывает метод
//базового класса с таким же именем.
//не следует путать с выделением памяти
{
base.Print(); //ключевое слово base позволяет получить
//доступ к члену базового класса
sc.WriteLine("The price is "+price);
sc.ReadLine();
}
}
class Prog
{
public static void Main()
{
Diamond ob1=new Diamond(10,4,99.99);
ob1.Print();
}
}
Итак, есть класс, описывающий камень и созданный на его основе класс, описывающий бриллиант. Конструктор с параметрами производного класса сначала запускает аналогичный конструктор базового класса, передавая ему нужные значения, затем производит свои действия:
public Diamond(float ww,int cc,decimal pp):base(ww,cc)
{price=pp;}
Здесь осуществляется вызов конструктора с параметрами базового класса. При этом базовому конструктору передаются аргументы, заданные в вызове производного конструктора. В таком контексте ключевое слово base имеет смысл ссылки на конструктор базового класса.
Наследование можно предотвратить, определив класс как sealed. Это ключевое слово указывает, что данный класс не может быть предком. Если мы определим класс Stone в нашей проге таким образом:
sealed class Stone
{
}
то производный класс Diamond не унаследует члены базового класса.
А теперь немного переделаем нашу прогу:
using sc=System.Console;
class Stone //это будет базовый класс
{
protected float weight;
protected int color;
public Stone(){weight=0;color=0;}//конструктор
public Stone(float w,int c) //конструктор
{
weight=w;
color=c;
}
public virtual void Print() //виртуальный метод вывода
{
sc.WriteLine("The weight is "+weight);
sc.WriteLine("The color number is "+color);
sc.ReadLine();
}
}
class Diamond:Stone //это производный класс
{
new int color;//закроем переменную базового класса
private double price;
public Diamond(){price=0;}
public Diamond(float ww,int cc,double pp):base(ww,cc)
{price=pp;}
public override void Print() //метод вывода.
//override говорит компилятору о том,
//что код наследованного метода
//будет переопределен.
{
sc.WriteLine("The weight is "+base.weight);
sc.WriteLine("The color number is "+base.color);
//ключевое слово base позволяет получить доступ
//и к членам базового класса, закрытым из-за
//объявления новой переменной с таким же
именем.
//base имеет смысл ссылки на базовый класс.
sc.WriteLine("The price is "+price);
sc.ReadLine();
}
}
class Prog
{
public static void Main()
{
Diamond ob1=new Diamond(10,4,99.99);
ob1.Print();
}
}
Теперь мы познакомились с виртуальными функциями.
Тут же я хочу отметить ключевые слова this и base. И то,
и другое имеет смысл ссылки на объект. Но разница в том, что this ссылается на текущий объект текущего класса
(того класса, типом которого является сам объект), а base ссылается на объект базового класса
(предка). Если не понятно,
- this - полноценный объект, с которым мы работаем;
- base - объект базового класса-предка.
Абстрактные классы. Как много страха выражают эти два слова для начинающего кодера! Но, на самом деле, бояться здесь нечего. Как уже отмечалось, абстрактный класс
- это класс, объект которого нельзя создать, может нести некоторую часть теоретической информации об объекте. Но зачем они нужны? На базе абстрактных классов можно создавать новые производные классы, на основе которых можно будет создавать объекты. Для создания абстрактного класса в C# используется ключевое слово abstract. Абстрактным можно определить и метод, используя все то же ключевое слово. Как уже было отмечено, абстрактный метод автоматически становится виртуальным. Итак, пример...