Таблица определяет вероятные варианты доступа к элементам базисного класса из элементов-функций производного класса и из прикладной программы, применяющей объекты производного класса.
Таблица. Атрибуты доступа к элементам базисного класса
Доступ в базисном классе | Тип базисного класса | Доступ из производного класса | Доступ пользователей производного класса |
public protected private public protected private | public public public private private private | public protected недоступен private private недоступен | дешёв недоступен недоступен недоступен недоступен недоступен |
Программа на рис. 3 демонстрирует работу правил доступа, представленных в таблице, для случая, в то время, когда класс Base есть общедоступным базисным классом.
При применении приватного базисного класса дополнительно к правилам, приведенным в таблице, для protected и public элементов базисного класса возможно вернуть их уровень доступа и в производном классе, в случае, если применять дополнительные объявления этих элементов в производном классе (рис. 4). Напомним, что по умолчанию базисный класс наследуется как приватный.
#include
using namespace std;
class Base {
private:
int privateMember;
protected:
int protectedMember;
public:
int publicMember;
};
class Derived:public Base {
public:
void f(){ cout
void g(){ cout
void h(){ cout
};
void main(){
Derived derived;
derived.privateMember=1; // неточность
derived.protectedMember=2; // неточность
derived.publicMember=3;
}
Рис. 3. Файл Derived1.cpp
#include
using namespace std;
class Base {
private:
int privateMember;
protected:
int protectedMember1,protectedMember2;
public:
int publicMember1,publicMember2;
};
class Derived : Base {
protected:
Base::protectedMember2;
public:
Base::publicMember2;
void f(){ cout
void g(){ cout
void h(){ cout
};
void main(){
Derived derived;
derived.privateMember=1; // неточность
derived.protectedMember2=2; // неточность
derived.publicMember1=3; // неточность
derived.publicMember2=4;
}
Рис. 4. Файл Derived2.cpp
Явные и неявные преобразования типов при наследовании
При применении наследования объект производного типа может рассматриваться как объект его базисного типа; обратное утверждение неверно. Для общедоступного базисного класса компилятор может неявно выполнить преобразование объекта производного типа к объекту базисного типа:
class Base { /*…*/) ;
class Derived : public Base { /*..*/} ;
void main() {
Derived derived;
Base base=derived;
. . .
Обратное преобразование — Base к Derived — должно быть выяснено программистом при помощи конструктора Derived (Base):
Derived tmp=base; // вызов конструктора
Напомним, что размеры объектов производного и базисного типов в большинстве случаев разны. Исходя из этого эргономичнее применять не объекты, а указатели (либо ссылки) на них, поскольку все указатели имеют однообразный размер. Также, в качестве элементов контейнерных классов значительно чаще употребляются не объекты, а указатели на них. Исходя из этого при наследовании самые актуальными являются преобразования типов указателей.
В случае, если базисный класс есть общедоступным базисным классом, то для пользователей производного и базисного типов правила преобразования указателей весьма несложны: неявно возможно выполнено преобразование указателя типа Derived* к указателю Base*; обратное преобразование непременно должно быть явным, к примеру:
class Base {/*…*/};
class Derived : public Base {/*…*/};
void main(){
Derived derived;
Base *bp=&derived; // неявное преобразование
Derived *dp_1=bp; // неточность
Derived *dp_2=(Derived*)bp; // явное преобразование
}
При применении общедоступного базисного класса производный класс рассматривается как то же, что и базисный класс, и для этих классов существуют предопределенные преобразования из Derived в Base, из указателя на Derived в указатель на Base, и из ссылки на Derived в ссылку на Base.
Применение указателей на базисный класс. Виртуальные функции
Концепция то же, что и — замечательный механизм абстракции, поскольку она разрешает во многих контекстах пользоваться производным классом как базисным. К примеру, в случае, если функция print(Base*) распечатывает определенные поля объектов базисного класса, то ее возможно применять и для объектов производного класса, к примеру:
Derived d;
. . .
print(d);
Но применение указателей на базисный класс для указания на объект производного класса ведет к тому, что через таковой указатель будет осуществляться доступ лишь к функциям-элементам базисного класса. Иначе говоря выбор функций-элементов класса будет определяться типом указателя, а не типом объекта, на что сейчас показывает указатель.
Программа Fruit.cpp (рис. 5) демонстрирует применение указателей типа fruit* для указания на объекты порожденных классов apple и orange. В следствии на экран будет трижды выведено слово Fruit, потому, что в цикле for будет трижды вызываться функция fruit::identify().
#include
using namespace std;
class fruit{
public:
char *identify(){ return Fruit; }
};
class apple:public fruit{
public:
char *identify(){ return Apple; }
};
public:
char *identify(){ return Orange; }
};
void main()
{
fruit* f_ptr[3];
f_ptr[0]=new fruit;
f_ptr[1]=new apple;
f_ptr[2]=new orange;
for(int i=0;i
cout
}
Рис. 5. Файл Fruit.cpp
Так, элемент-функция вызывается в зависимости от типа указателя либо ссылки, использованной для доступа к ней, а не от текущего типа объекта, на что ссылается указатель либо ссылка. Это еще раз демонстрирует следующий пример:
fruit *fp=new apple;
fp-identify(); // возвращает Fruit
((apple*)fp)-identify(); // возвращает Apple
apple *ap=(apple*)fp;
ap-identify(); // возвращает Apple
Программа Fruit.cpp обязана верно идентифицировать фрукты, а для этого нужно, дабы соответствующая идентифицирующая функция определялась типом текущего объекта, а не типом ссылки либо указателя, использованных для доступа к нему. Эта цель будет достигнута, в случае, если функцию identify() выяснить в базисном классе как виртуальную:
class fruit {
public:
virtual char *identify() { return Fruit; )
};
С добавлением главного слова virtual в объявлении fruit::identify() программа Fruit.cpp будет трудиться так, как мы желали, печатая слова — Fruit, Apple, Orange.
Напомним, что функции apple::identify и orange::identify кроме этого являются виртуальными, не смотря на то, что мы их очевидно не объявляем. Правило для определения, в то время, когда функция виртуальная, следующее: функция есть виртуальной, если она заявлена виртуальной, либо имеется функция из базисного класса с той же сигнатурой, которая есть виртуальной. Сигнатура функции складывается из ее типов и имени формальных доводов.
Применение виртуальных функций ведет к тому, что на этапе компиляции нереально будет выяснить, какая виртуальная функция (базисного либо производного класса) будет выполняться. Данный выбор будет производиться на этапе исполнения программы и он носит название позднего (динамического) связывания имен виртуальных функций.
Для виртуальных функций возвращаемый тип функции производного класса обязан соответствовать типу результата функции базисного класса. Это гарантирует, что динамическое ( на протяжении исполнения ) связывание имен, создаваемое виртуальными функциями, сохраняет тип.
Довольно часто конкретно использование производных классов и виртуальных функций именуется объектно-ориентированным программированием. Базисный класс определяет интерфейс (множество функций), для которого производные классы снабжают комплект реализаций. Возможность выбора одной из виртуальных функций время от времени именуют главным (чистым) полиморфизмом.
ОБОРУДОВАНИЕ
ПК: процессор с частотой 1,6ГГц либо выше, 1024 МБ ОЗУ, жесткий диск со скоростью 5400 об/мин, видеоадаптер с помощью DirectX 9 и с разрешением 1280 х 1024 (либо более высоким), ОС Windows 7, интегрированные среды разработки приложений Visual Studio 2010 и Visual Studio Team System 2008 с наборами документации MSDN, каталог Tprog\Lab5, содержащий исходные файлы проектов в подкаталогах Arr_bnd (Array.h, Array.cpp, Arrbnd.h, Arrbnd.cpp, Arrbprog.cpp) и Derived (Derived1.cpp, Derived2.cpp, Fruit.cpp), файл Labtprog5.doc (методические указания к данной лабораторной работе), не меньше 200 Mб свободной памяти на логическом диске, содержащем каталог Tprog\Lab5.
ЗАДАНИЕ НА РАБОТУ
4.1. Ознакомиться с разработкой наследования и включения на неуправляемом (unmanaged) языке Visual С++ в интегрированной среде разработки приложений Visual Studio 2010 в ходе создания приложений Arr_bnd, Derived1, Derived2, Fruit.
4.2. Создать и отладить объектно-ориентированную программу на неуправляемом (unmanaged) языке С++ в интегрированной среде разработки приложений Visual Studio 2010 в соответствии с заданием учителя. Примерами заданий смогут быть следующие.
1. Написать тексты h-файлов и cpp-файлов для базисного класса Point и производного класса Rect (прямоугольник). Описание классов:
Класс | Элементы данных | Интерфейс |
Point | x, y | Конструкторы, функции move, assign, print |
Rect | dx, dy | Конструкторы, функция square, операции =, +=, |
Создать и отладить программу с примерами использования и создания объектов классов Point и Rect.
2. Написать тексты h-файлов и cpp-файлов для базисного класса Point и производного класса Rect (прямоугольник). Описание классов:
Класс | Элементы данных | Интерфейс |
Point | x, y | Конструкторы, функции move,print, операции =, +=, == |
Rect | p2(типа Point) | Конструкторы, функции move, square, операции =, |
Создать и отладить программу с примерами использования и создания объектов классов Point и Rect.
3. Написать тексты h-файлов и cpp-файлов для базисного класса Point и производного Circle (окружность). Описание классов:
Класс | Элементы данных | Интерфейс |
Point | x, y | Конструкторы, операции +=, =, |
Circle | r | Конструкторы, friend-функции move, square, операции =, ==, print |
Создать и отладить программу с примерами использования и создания объектов классов Point и Circle.
4. Создать базисный класс Point и производный класс Rect (прямоугольник)., разрешающие применять их в следующей программе:
Point p1, p2(3,11), p3=p2; (p2.move(10,10)).print(); p3.print(); p1=p2;
Rect r1, r2(p1,p2), r3=r2; cout
Написать тексты h-файла и cpp-файла для классов Point и Rect. Создать и отладить использования и программу создания объектов классов Point и Rect.
5. Создать базисный класс Point и производный класс Circle (окружность), разрешающие применять их в следующей программе:
Point p1(10,20), p2; p2=2*p1 + Point(20,30); cout
Circle r1, r2(p1,p2), r3=r2; cout
Написать тексты h-файла и cpp-файла для классов Point и Circle. Создать и отладить использования и программу создания объектов классов Point и Circle.
ПОРЯДОК Исполнения РАБОТЫ
5.1. Проверить наличие на компьютере нужного программного обеспечения и аппаратного оборудования, наличие 200 Мб свободной памяти на логическом диске, содержащем каталог Tprog\Lab5, наличие файла Labtprog5.doc и исходных файлов в подкаталогах Arr_bnd (Array.h, Array.cpp, Arrbnd.h, Arrbnd.cpp, Arrbprog.cpp) и Derived (Derived1.cpp, Derived2.cpp, Fruit.cpp) каталога Tprog\Lab5.
5.2. Создать персональный каталог, в котором будут размещаться создаваемые на протяжении лабораторной работы проекты.
5.3. Создать в личном каталоге безлюдной проект неуправляемого консольного приложения, выбирая в IDE-среде в меню File следующую последовательность опций: New-Project- Other Language -Visual C++ — Win32 — Win32 Console Application — Empty Project, а после этого добавить в него исходные файлы одного из каталогов, предварительно сделав копирование их в каталог проекта. По команде Ctrl+F5 откомпилировать проект и выполнить приложение. Проверить правильность работы приложения.
5.4. Повторить исполнение пункта 5.3 для остальных приложений.
5.5. Создать и отладить объектно-ориентированную программу на неуправляемом (unmanaged) языке С++ в интегрированной среде разработки приложений Visual Studio 2010 в соответствии с заданием учителя. В случае, если при отладке появляются неприятности с устранением неточностей в программе, нужно выделить неточность в окне Error List и надавить клавишу F1. В показавшемся окне документации MSDN будет приведены примеры исправления неточности.
ОФОРМЛЕНИЕ ОТЧЕТА
Отчет обязан содержать:
- цель работы и личное задание;
- тексты исходных файлов, которые содержат описание и реализацию классов, применяемых в лабораторной работе;
- файлы *.h и *.cpp, которые содержат описание и реализацию классов в соответствии с заданием учителя;
- текст тестовой программы и результаты работы программы;
- краткая информация о механизмах наследования и включения.
КОНТРОЛЬНЫЕ ВОПРОСЫ
7.1. В чем содержится наследование? Как реализуется расширение либо специализация интерфейса базисного класса?
7.2. В каком порядке производится инициализация данных при порождении объекта производного класса?
7.3. Как производится наследование операторных функций базисного класса классом Arr_bnd?
7.4. По какой причине нужна перегрузка оператора индексации [] для класса Arr_bnd?
7.5. Какие конкретно правила существуют для доступа к элементам базисного класса из элементов-функций производного класса и из прикладной программы, применяющей объекты производного класса?
7.6. Какие конкретно правила существуют для явного и неявного преобразования типов данных при наследовании?
7.7. Какие конкретно правила существуют для доступа к функциям базисного и производных классов?
БИБЛИОГРАФИЧЕСКИЙ ПЕРЕЧЕНЬ
1. Подбельский, В.В. Язык Си+ : учеб.пособие для институтов / В.В.Подбельский .— 5-е изд. — М. : статистика и Финансы, 2007 (2001, 2002, 2003, 2004, 2005, 2006).— 560с. : ил.
2. Павловская, Т.А. C/C++:Программирование на языке большого уровня : учебник для институтов / Т.А.Павловская .— М.[и др.] : Питер, 2007 (2002, 2003, 2004, 2005, 2006) .— 461с. : ил.3. Гарнаев А.Ю. Самоучитель Visual Studio .Net 2003. – СПб.: БХВ-Петербург, 2003. – 688 с.
3. Шилдт, Г. C+ : базисный курс / Г.Шилдт;пер.с англ.и ред.Н.М.Ручко .— 3-е изд. — М.[и др.] : Вильямс, 2007 (2005) .— 624с. : ил.5. Уоткинз Д., Хаммонд М., Эйбрамз Б. Программирование на платформе .NET. – М.: Издательский дом Вильямс, 2003. – 368 с.
4. MSDN 2010. Электронная документация Микрософт для разработчиков ПО. – 500000 с.
5. Пол Айра. Объектно-ориентированное программирование с применением языка С++: Пер. с англ.- К.: НИПФ ДиаСофтЛтд.,1998. — 480 с.
6. Г. Шилдт. практика и Теория С++ : Пер. с англ. – СПб.: BHV – Петербург, 1999. – 416 с.
7. Цимбал А.А., Майоров А.Г., Козодаев М.А. Turbo C++:Пер. с англ.-М.: Джен Ай Ltd, 1993.- 512с.
8. С.Дьюхарст, К.Старк. Программирование на С++:Пер. с англ.- Киев: ДиаСофт, 1993. — 272с.
ЛАБОРАТОРНАЯ РАБОТА N 6
Объектно-ориентированное программирование на языке C# 2.0.
ЦЕЛЬ И ЗАДАЧИ РАБОТЫ
практическое освоение и Изучение средств и приёмов объектно-ориентированного программирования на базе языка C# и инструментальной среды разработки MS Visual Studio .NET 2010.
ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Выполняющая среда для языка C#
На языке C# создаются управляемые приложения, каковые выполняются в Микрософт CLR. Среда CLR (Common Language Runtime — общеязыковая выполняющая среда) — это виртуальная выполняющая совокупность (Virtual Execution System — VES), реализующая CLI (Common Language Infrastructure – неспециализированная инфраструктура языка). В CLR предоставляется множество эргономичных средств для управляемых приложений, включая, кроме другого, четко налаженный сборщик мусора для управления памятью, уровень безопасности доступа к коду, развитую самоописательную совокупность типов.
В стандарт CLI входит кроме этого файловый формат РЕ (Portable Executable — переносимый исполняемый модуль) для управляемых модулей. Так, в конечном итоге, возможно скомпилировать программу С# на платформе Windows, а делать и на Windows, и на Linux, причем без перекомпиляции, потому, что кроме того формат файлов есть стандартизованным.
Дабы обеспечить функциональную совместимость между различными языками, в CLI выяснено подмножество неспециализированной совокупности типов (Common Type System — CTS), которое именуется спецификацией неспециализированного языка (Common Language Specification — CLS).
Среда CLR — это не интерпретатор. Она не создаёт повторную трансляцию кода IL при каждом его исполнении. CLR в конечном итоге компилирует код IL в машинный код, перед тем как делать его, т.е. осуществляет JIT-компиляцию.
Сборка (assembly) — это дискретная единица многократно применяемого кода в CLR. По собственной природе она подобна DLL-библиотеке из мира неуправляемого кода, но на этом все сходство заканчивается. Сборка может складываться из множества модулей, каковые объединяет совместно манифест, обрисовывающий содержимое сборки. С позиций ОС, модуль аналогичен DLL-библиотеке. Сборки смогут иметь присоединенные к ним версии, что разрешает идентифицировать одноименные сборки, но с различными предположениями, как отдельные. Сборки кроме этого содержат метаданные, обрисовывающие содержащиеся в них типы. При поставке родной DLL-библиотеки, написанной на неуправлямом языке, в нее в большинстве случаев включается заголовочный файл и/либо документация, обрисовывающая экспортированные функции. Метаданные удовлетворяют этим требованиям, абсолютно обрисовывая типы, содержащиеся в сборки. Другими словами, сборки — это снабженные предположениями, самоописательные единицы многократно применяемого кода в среде CLR.
Именовать сборки возможно двумя главными методами.
- Строгое (полное) именование. Такая сборка имеет имя, складывающееся из четырех частей: краткое имя сборки, номер версии, идентификатор культуры в формате ISO и хеш-маркер. В случае, если имя сборки складывается из всех четырех частей, она считается строго именованной.
- Частичное именование. Такая сборка имеет имя, в котором опущены кое-какие подробности строго именованной сборки.
Преимущество строго именованных сборок пребывает в том, что они смогут быть зарегистрированы в глобальном кэше сборок (Global Assembly Cache — GAC) и стать дешёвыми для применения всеми приложениями совокупности. Регистрация сборки в GAC подобна регистрации в системном реестре СОМ-сервера. В случае, если сборка не есть строго именованной, то приложение может применять ее только локально. Иначе говоря сборка обязана пребывать где-то в каталоге приложения, применяющего ее, или в его подкаталогах. Такие сборки довольно часто именуют приватными.
Предположения играются важную роль на протяжении загрузки сборок, и все сборки снабжены информацией о версии. Механизм контроля предположений был встроен в загрузчик CLR изначально, и это исключает такую неприятность, которая именуется адом DLL (DLL Hell), в то время, когда замена совместно применяемой DLL-библиотеки ее новой версией ведет к нарушению работы приложений, пользующихся ветхой версией данной библиотеки.
В CLR множество предположений одной и той же сборки смогут мирно сосуществовать на одной и той же машине без каких-либо распрей между собой. Более того, приложения по умолчанию смогут выбирать применение самый свежей версии, имеющейся на машине, либо же показывать правильную версию, используя политику предположений в собственных конфигурационных файлах.
Метаданные — это расширяемый формат описания содержимого сборок. Посредством метаданных возможно приобретать доступ и изучить определения типов и присоединенные к ним атрибуты. Метаданные смогут сказать о том, поддерживает ли определенный класс объекта конкретный способ, перед тем как пробовать позвать его, или порожден ли этот класс от какого-либо другого. Процесс просмотра метаданных именуется рефлексией. В большинстве случаев рефлексия типов в сборке начинается с объекта System.Type.
Взять один из этих экземпляров типов возможно посредством главного слова С# typeof, вызова System. Assembly. GetType () либо нескольких вторых способов. В общем случае главное слово typeof более действенно, в силу того, что вычисляется на протяжении компиляции, тогда как способ GetType (), не смотря на то, что и есть более эластичным, потому, что ему возможно передавать произвольную строчок, запускается на протяжении исполнения. По окончании получения объекта типа возможно выяснить, есть ли он классом, интерфейсом, структурой и т.п., какие конкретно способы у него имеется, и типы и количество содержащихся в нем полей.
Определение классов в языке C#
Определения классов в С# похожи на определения классов в C++ и Java. Дабы вы имели возможность взять представление об этом, разглядим несложный класс. В следующем коде продемонстрированы базисные части, из которых состоит определение класса.
// ПРИМЕЧАНИЕ: данный код не рекомендован для компиляции в том виде, как имеется
[Serializable]
public class Derived : Base, ICloneable
{
private Derived( Derived other ) {
this.x = other.x;
}
public object Clone () { // реализует интерфейс IClonable.Clone
return new Derived( this );
}
private int x;
}
Это объявление класса определяет класс Derived, унаследованный от класса Base и кроме этого реализующий интерфейс ICloneable.
Модификатор доступа перед главным словом class руководит видимостью типа извне сборки. Класс Derived есть общедоступным, а это указывает, что пользователи сборки, содержащей данный класс, смогут создавать его экземпляры. Данный тип содержит приватный (private) конструктор, применяемый общедоступным (public) способом Clone, что реализует интерфейс ICloneable. В то время, когда класс реализует интерфейс, это значит, что пригодится реализовать все способы этого интерфейса.
Практически к любой именованной сущности в совокупности типов CLR возможно использовать атрибуты. В этом случае атрибут Serializable был применен к классу, дабы показать пример применения синтаксиса атрибутов. Эти атрибуты становятся частью метаданных, обрисовывающих тип для его потребителей. Вдобавок возможно создавать личные атрибуты для присоединения их к разным сущностям, таким как классы, параметры, возвращаемые значения и поля, что позволяет без проблем реализовать возможности аспектно-ориентированного программирования (Aspect Oriented Programming — АОР).
Поля (field) — это механизм, воображающий состояние объектов. В большинстве случаев новый класс объявляется лишь тогда, в то время, когда необходимо смоделировать новый тип объекта, с собственным внутренним состоянием, представленным его полями экземпляра.
Поля объявляются с типом подобно тому, как это делается со всеми другими переменными. Ниже перечислены допустимые модификаторы полей:
new
public
protected
internal
private
static
readonly
volatile
Инициализировать поля на протяжении создания объекта возможно разными методами.
Несложный метод сделать это — прибегнуть к помощи инициализаторов. Они задаются в точке определения поля и смогут использоваться как для статических полей, так и для полей экземпляра, к примеру:
private int x = 789;
private int у;
private int z = A.InitZO;
Статические readonly-поля инициализируются в статическом конструкторе, а readonly-поля экземпляра — в конструкторе экземпляра. В качестве альтернативы такие поля возможно инициализировать при помощи инициализаторов в точке их объявления в классе, как это делается с другими полями. В конструктора возможно какое количество угодно раз присваивать значения полям readonly. Лишь в конструктора поле readonly возможно передать второй функции как параметр ref (параметр передается в функцию и возвращается) либо out (возвращаемый параметр). Напомним, что по умолчанию параметр относится к параметру in (передаваемый в функцию). Разглядим пример:
public class A
{
public A()
{
this.у = 456;
// Возможно кроме того еще раз установить у.
this.у = 654;
// Возможно применять у как параметр ref.
SetField( ref this.у );
}
private void SetField( ref int val )
{
val = 888;
}
private readonly int x = 123;
private readonly int y;
public const int z = 555;
{
A obj = new A () ;
System.Console.WriteLine ( x = {0}, у = {1}, z = {2},
obj.x, obj.y, A.z );
}
}
Тут направляться отметить один серьёзный нюанс: поле z заявлено с главным словом const. Сначала может показаться, что эффект от этого будет тем же, что и от readonly, но в действительности это не верно. Во-первых, поле const известно и употребляется на протяжении компиляции. Это значит, что код, сгенерированный компилятором в процедуре Main, возможно оптимизирован заменой всех случаев применения данной переменной ярким константным значением. Компилятор вправе предпринять таковой трюк для увеличения производительности — легко по причине того, что значение данного поля известно на момент компиляции. К тому же обратите внимание, что доступ к полю const осуществляется с указанием имени класса, а не имени экземпляра. Обстоятельство в том, что значения const являются неявно статическими и не воздействуют на отпечаток памяти либо форму экземпляров объекта. Опять-таки, это имеет суть, потому, что компилятор оптимизирует доступ к участку памяти в экземпляре объекта, потому, что это поле будет все равно однообразным у всех экземпляров объекта.
Конструкторы вызываются при начальной загрузке класса средой CLR либо при создании объекта. Существуют два типа конструкторов: конструкторы экземпляра и статические конструкторы. Класс может иметь лишь один статический конструктор, не имеющий параметров. Он вызывается, в то время, когда CLR загружает тип. Имя статического конструктора должно совпадать с именем класса, к которому он в собственности. Как и к любому второму участнику класса, к статическому конструктору возможно присоединять атрибуты метаданных.
Иначе, конструкторы экземпляра вызываются при создании экземпляра класса. В большинстве случаев они устанавливают состояние объекта за счет инициализации полей в желательное предопределенное состояние. Возможно кроме этого предпринять каждые другие действия по инициализации, такие как подключение к базе данных и открытие файла. У класса возможно пара конструкторов экземпляра, каковые смогут быть перегружены (т.е. иметь различные типы параметров). Подобно статическим конструкторам, конструкторы экземпляра именуются по заглавию определяющего их класса. Одна заслуживающая упоминания особенность конструкторов экземпляра пребывает в необязательности выражения инициализатора. Посредством инициализатора, что следует за двоеточием по окончании перечня параметров, возможно позвать конструктор базисного класса либо второй конструктор того же класса, показывая, соответственно, главные слова base и this. Разглядим следующий пример кода с двумя комментариями:
class Base
{
public int x = InitX();
public Base ( int x )
{
this.x = x; // устранение неоднозначности между
// параметром и переменной экземпляра
}
}
class Derived : Base
{
public Derived( int a )
:base( a ) // вызов конструктора базисного класса
{
}
}
Способ определяет процедуру, которую возможно выполнить над объектом либо классом. В случае, если способ есть способом экземпляра, то его возможно вызывать на объекте. В случае, если же способ статический, его возможно вызывать лишь на классе. Отличие между ними в том, что способ экземпляра имеет доступ и к полям экземпляра объекта, и к статическим полям класса, тогда как статический способ не имеет доступа к методам и полям экземпляра. Статические способы смогут иметь доступ лишь к статическим участникам класса.
В следующем примере демонстрируется использование способа экземпляра:
public class A
{
private void SomeOperation()
{
x = 1;
this.у = 2;
z = 3;
// присваивание this в объектах есть неточностью
// A newinstance = new A() ;
// this = newinstance;
}
private int x;
private int y;
private static int z;
static void Main()
{
A obj = new A () ;
obj.SomeOperation();
System.Console.WriteLine ( x = {0}, y= {1}, z= {2},
obj. x, obj.y, A.z ) ;
}
}
В способе Main создается новый экземпляр класса А и после этого вызывается способ SomeOperation через экземпляр этого класса. В тела способа SomeOperation имеется доступ к статическим полям и полям экземпляра класса, исходя из этого присваивать им значения возможно легко с применением их идентификаторов. Не обращая внимания на то что, как уже упоминалось, в способе SomeOperation возможно присваивать значение статическому участнику z, не квалифицируя его, с целью достижения лучшей читабельности кода на протяжении присваивания значений направляться квалифицировать статические поля кроме того в способах, относящихся к тому же самому классу. Поступив так, вы поможете тем, кому нужно будет сопровождать код, даже в том случае, если это станете вы сами!
Обратите внимание, что при присваивании значения поле у снабжается префиксом — идентификатором this. Посредством this возможно обращаться к полям экземпляра, как было продемонстрировано в прошлом примере кода. Потому, что значение this доступно лишь для чтения, ему нельзя присвоить что-либо, что вынудит его ссылаться на другой экземпляр. При попытке сделать это компилятор скажет об неточности, и код не скомпилируется.