Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Экзамен в гаи redacted.doc
Скачиваний:
5
Добавлен:
27.09.2019
Размер:
676.35 Кб
Скачать

2. Наследование классов. Синтаксис и общий смысл.

Наследование (inheritance) является одним из самых важных механизмов в ООП. Любой класс может наследоваться от другого класса, а это значит, что он будет иметь все те же члены, что и класс, от которого он унаследован. В терминологии ООП класс, от которого наследуется другой класс (или, другими словами, создается производный класс) называется родительским или базовым классом. Важно обратить внимание на то, что в С# напрямую наследоваться классы могут только от одного базового класса, хотя у базового класса может быть свой собственный базовый класс и т.д.

Механизм наследования позволяет расширять или создавать специфические клас­сы от одного более общего базового класса. Например, возьмем класс, представляю­щий животное с фермы. Этот класс мог бы называться Animal и обладать методами вроде EatFood() или Breed(). От него можно было бы создать производный класс по имени Cow , который бы поддерживал все те же самые методы, но при этом также имел и свои собственные, например, Моо() и SupplyMilk(), а также еще один производный класс по имени Chicken с методами Cluck() и LayEgg()..

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

public class MyClass : MyBase {

// Члены класса.

}

В определениях классов разрешено указывать только один базовый класс и в случае наследования от абстрактного класса нужно обязательно реализовать все наследуемые абстрактные члены (если только производный класс тоже не является абстрактным).

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

public class MyBase {

// Члены класса.

}

internal class MyClass : MyBase {

// Члены класса.

}

А приведенный ниже код скомпилировать не удастся:

internal class MyBase {

// Члены класса.

}

public class MyClass : MyBase {

// Члены класса.

}

Если базовый класс не используется, класс наследуется только от базового клас­са System.Object (который в С# имеет псевдоним object). В конечном счете, класс System.Object является корневым в иерархии наследования абсолютно всех классов.

3. Какой метод выберет компилятор?

class A { public void Test(int n) { Console.WriteLine("A"); } }

class B : A { public void Test(double n) { Console.WriteLine("B"); } }

static void Main(string[] args)

{

B b = new B();

b.Test(5);

}

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

Экзаменационный билет №8

1. Массивы. Строки. Потоки и файлы.

Массив – это проиндексированный список переменных, хра­нящихся в единственной переменной типа массива. Массивы имеют один единственный базовый тип, т.е. все отдельные вхождения в массиве относятся к одному и тому же типу.

Объявляются массивы следующим образом:

<базовый_тип> [] <имя>;

Массивы должны обязательно инициализироваться перед тем, как к ним можно будет получить доступ. Получать доступ к отдельным членам этого массива можно будет указанием их индекса в квад­ратных скобках:

<имя_массива>[<индекс>]

Инициализировать массив можно двумя способами: указанием всего содержи­мого массива в литеральной форме либо указанием размера массива и применением ключевого слова new для инициализации всех его элементов.

Спецификация массива с использованием литеральных значений подразумевает предоставление заключенного в фигурные скобки списка разделенных запятыми зна­чений для элементов:

int [] myIntArray = {5, 9, 10, 2, 99};

Второй подход требует применения следующего синтаксиса:

int [] myIntArray = new int [5];

При желании оба подхода можно комбинировать:

int [] myIntArray = new int[5] {5, 9, 10, 2, 99};

Многомерным называется такой массив, в котором для получения доступа к элемен­там применяется несколько индексов.

<базовый_тип> [,] <имя>;

<базовый_тип> [, , , ] <имя>;

double[,] hillHeight = new double[3,4];

double [,] hillHeight = {{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}};

Многомерные массивы считают­ся прямоугольными, потому что каждая «строка» имеет одинаковый размер. Синтаксис для объявления массивов, состоящих из массивов, подразумевает указа­ние в объявлении массива нескольких пар квадратных скобок:

int[][] jaggedIntArray;

jaggedIntArray = new int[3] [] {new int [] {1, 2, 3}, new int [] {1}, new int [] {1, 2}};

Манипулирование строками. Переменная типа string может воспри­ниматься как доступный только для чтения массив переменных char. Это означает, что доступ к отдельным символам можно получать с использованием приблизительно такого синтаксиса:

string myString = "A string";

char myChar = myString [1];

Как и в случае массивов, получать информацию о количестве элементов в строке также можно с помощью myString.Length. Другие базовые приемы манипулирования строками подразумевают использование команд в формате, подобном <строка>.ToCharArray(). К числу наиболее простых, но полезных из них относятся команды <строка>.ToLower() и <строка>.ToUpper().Для удаления пробелов в начале и конце строки может использоваться команда <строка>.Trim().

Весь ввод и вывод в .NET Framework подразумевает использование потоков. Поток (stream) - это абстрактное представление последовательного устройства. Последовательное устройство (serial device) — это нечто такое, что хранит данные в линейной манере и точно таким же образом обеспечивает доступ к ним: по одному байту за раз. Это устройство может быть дисковым файлом, сетевым каналом, местом в памяти или любым другим объектом, поддерживающим чтение и запись в линейном режиме. Сохранение устройства абстрактным означает, что лежащие в основе источник/приемник данных могут быть скрыты. Такой уровень абстракции обеспечивает повторное использование кода и позволяет писать более обобщенные процедуры, потому что нет необходимости заботиться о действительной специфике передачи данных. Таким образом, исходный код может быть передан и повторно использован, когда приложение читает из входного файлового потока, сетевого входного потока или любого другого вида потока.

Существуют два типа потоков:

  • Выходные. Используются, когда данные пишутся в некоторое внешнее место назначения, которым может быть физический дисковый файл, местоположение в сети, принтер или другая программа.

  • Входные. Используются для чтения данных в память или переменные, к которым может обращаться ваша программа. Наиболее часто используемая форма входного потока - клавиатура. Концепции, применимые к чтению/записи дисковых файлов, применимы к большинству устройств.