- •Программирование на языке c# в среде microsoft visual studio 2005
- •Оглавление
- •1 . Базовые элементы языка c#
- •1.1. Структура программы
- •Типы данных
- •1.3. Арифметические и логические операции
- •1.4. Условный оператор и оператор выбора
- •1.5. Ввод/вывод в консольном режиме
- •1.6. Комментарии
- •1.7. Массивы
- •1.8. Операторы цикла
- •1.9. Работа со ступенчатыми массивами
- •Контрольные вопросы
- •2. Работа с функциями
- •2.1. Общие принципы
- •2.2. Процедурное программирование в c#
- •Контрольные вопросы
- •3. Объектно-ориентированное программирование на c#
- •3.1. Общие принципы
- •3.2. Объявление и работа с классами
- •3.3. Перегрузка операторов
- •3.4. Индексаторы
- •3.5. Свойства
- •3.6. Использование класса в качестве типа данных
- •3.7. Работа со структурами
- •3.8. Наследование
- •3.9. Ссылки на объекты
- •3.10. Конструктор копирования
- •3.11. Виртуальные методы
- •3.12. Абстрактные методы и классы
- •3.13. Интерфейсы
- •3.14. Делегаты и события
- •3.15. Исключительные ситуации
- •Контрольные вопросы
- •4. Среда Microsoft Visual Studio 2005
- •4.1. Простейший пример
- •4.2. Средства управления работой программы
- •4.3. Создание меню
- •4.4. Ввод/вывод массивов
- •4.4.1. Ввод/вывод и обработка одномерного массива-строки
- •4.4.2. Ввод/вывод и обработка одномерного массива-столбца
- •4.4.3. Ввод/вывод и обработка двумерного массива
- •4.4.4. Форматированный ввод/вывод двумерного массива
- •4.5. Создание многооконных приложений
- •4.5.1. Создание sdi-приложения
- •4.5.2. Создание mdi-приложения
- •Контрольные вопросы
- •5. Объектно-ориентированное программирование в Microsoft Visual Studio 2005
- •5.1. Дополнение класса формы средствами решения прикладной задачи
- •5.2. Создание отдельных классов
- •5.3. Передача в классы указателей на формы
- •5.4. Создание форм в классах пользователя
- •Контрольные вопросы
- •Заключение
- •Библиографический список
3.7. Работа со структурами
Класс является ссылочным типом: доступ к его объектам осуществляется с помощью ссылок. Доступ к объектам класса с помощью ссылок вызывает дополнительные накладные расходы при каждом доступе. При работе с маленькими объектами дополнительные расходы могут иметь существенное значение. С целью решения этой проблемы в C# введены структуры. Структура подобна классу, но она имеет тип «значение», но не «ссылка». Внешне объявление структуры похоже на объявление класса. Структуры могут иметь в своем составе данные, методы, индексаторы, свойства. Конструкторы тоже разрешены, но они обязательно должны иметь параметры; деструкторы – нет. Для создания экземпляра структуры можно вызвать конструктор через new, но можно и не вызывать. В таком случае экземпляр структуры создается, но записанные в конструкторе операции не будут выполнены. Структуры не могут участвовать в процессе наследования ни в качестве предков, ни в качестве потомков. Исключение: в качестве предка структуры можно указать интерфейс (об интерфейсах поговорим позже).
namespace StructFun
{
struct dan1
{
public string s1; // атрибут public обязателен
public int k;
}
class Program
{
static dan1[] inpt()
{ // ввод массива структур
dan1[] temp;
int n;
Console.Write("Elements ? ");
n = Convert.ToInt32(Console.ReadLine());
temp = new dan1[n];
for (int i = 0; i < n; i++)
{
Console.Write("Elem " + i + " Num ");
temp[i].k = Convert.ToInt32(Console.ReadLine());
Console.Write("Elem " + i + " Name ");
temp[i].s1 = Console.ReadLine();
}
return temp;
}
static double proc1(dan1 []x)
{ // обработка массива структур
int s = 0;
for (int i = 0; i < x.Length; i++)
s += x[i].k;
return (double)s / x.Length;
}
static void Main(string[] args)
{
dan1[] id; // массив исходных данных
double aver;
id = inpt(); // ввод исходных данных
aver = proc1(id); // обработка массива структур
Console.WriteLine("Average=" + aver);
Console.ReadLine();
} } }
3.8. Наследование
В C# допускается простое наследование: каждый класс может иметь только одного предка. Используя наследование, можно создать базовый класс, который определяет характеристики, присущие множеству связанных объектов. Этот класс затем может быть унаследован другими классами с добавлением в каждый из них своих особенностей. Равнозначные термины: базовый класс – класс-наследник; родительский класс – дочерний класс; класс предок – класс-наследник.
Создадим в качестве примера базовый класс для обработки массива, включающий определение массива, его ввод и вывод. К элементам базового класса с атрибутом доступа private нет доступа из классов-наследников, они, таким образом, не наследуются. Поэтому рекомендуют (если нет на этот счет особых соображений) дать элементам базового класса атрибут доступа protected.
class arr
{
protected int[] k; /* атрибут доступа protected
необходим для обеспечения доступа из классов-наследников */
public arr()
{ // конструктор 1
int n;
Console.Write("Элементов ? ");
n = Convert.ToInt32(Console.ReadLine());
k = new int[n];
for (int i = 0; i < n; i++)
{
Console.Write("K[" + i + "]=");
k[i] = Convert.ToInt32(Console.ReadLine());
}
}
public arr(int p)
{ // конструктор 2
k = new int[p];
for (int i = 0; i < p; i++)
{
Console.Write("K[" + i + "]=");
k[i] = Convert.ToInt32(Console.ReadLine());
}
}
public void output()
{
Console.WriteLine();
Console.WriteLine("Elements of Array");
for (int i = 0; i < k.Length; i++)
Console.WriteLine("K[" + i + "]=" + k[i]);
} }
На его базе можно построить классы обработки массивов. В нашем случае – нахождение суммы. Класс-наследник включает все данные своего предка (за исключением данных с атрибутом доступа private). Наследуются по общим правилам и индексаторы, и свойства, а также методы перегрузки операторов.
class proc1 : arr // задаем базовый класс arr
{
int q;
public proc1()
{ // конструктор класса-наследника
Console.Write("Граница ");
q = Convert.ToInt32(Console.ReadLine());
}
public int sum()
{
int s = 0;
for (int i = 0; i < k.Length; i++)
if (k[i] > q) s += k[i];
return s;
} }
Использование созданных классов
class Program
{
static void Main(string[] args)
{
proc1 My = new proc1(); // 1
int s1;
My.output(); // обращение к методу предка
s1=My.sum(); /* обращение к собственному методу,
аналогично можно обращаться и к свойствам предка */
Console.WriteLine("Summa= " + s1);
Console.ReadLine();
} }
При создании экземпляра класса, имеющего предка (строка // 1), запускаются все конструкторы: в первую очередь – конструктор базового класса и затем конструктор класса-наследника. В нашем случае это означает, что будет осуществлен ввод сначала массива и вслед за ним – границы. При наличии большего количества уровней наследования подряд будут запущены конструкторы всех уровней иерархии, начиная с базового.
Если конструкторы не имеют формальных параметров, то при этом никаких проблем не возникает: каждый конструктор независимо от других выполняет свои операторы. Осталось решить вопрос: как обеспечить передачу параметра (ов) конструктору класса-предка, в нашем случае – конструктору 2 ? Проще всего это выполнить с помощью списка инициализации в конструкторе класса-наследника.
public proc1(int k1, int k2): base(k1)
{
q = k2;
}
Запись base(k1)означает, что конструктору базового класса в качестве фактического параметра будет передано значение к1. Пример главной функции в этом случае:
static void Main(string[] args)
{
int s1;
proc1 Myaa = new proc1(6, 20); //обращение к
// конструктору с параметрами
Myaa.output();
s1=Myaa.sum();
Console.WriteLine("Summa= " + s1);
Console.ReadLine();
}
Лучше всего придерживаться следующего правила: при написании конструктора класса-наследника необходимо позаботиться о параметрах непосредственного предка. Таким образом даже при большом количестве уровней иерархии будет обеспечена согласованная работа конструкторов.