
- •Глава 10, описывающая классы как контейнеры их статических членов,
- •Глава 13 посвящена отношениям между классами (и их объектами). Особое
- •Глава 18 включена в книгу при подготовке второго издания. Она посвящен
- •Глава 1. Объектная ориентация программ
- •1.1. Типы, классы, объекты
- •1.2. Программа на c#
- •1.3. Пространство имен
- •1.4. Создание консольного приложения
- •Глава 2. Типы в языке c#
- •2.1. Типы ссылок и типы значений
- •2.2. Классификация типов c#
- •2.3. Простые типы. Константы-литерал
- •2.4. Объявления переменных и констант базовых типо
- •If implicit in int interface
- •Internal is lock long namespace
- •Volatile while
- •Глава 3. Операции и целочисленные выражения
- •3.1. Операции языка c#
- •3.2. Операции присваивания и оператор
- •3.4. Выражения с арифметическими операциями
- •3.6. Переполнения при операциях с целыми
- •Глава 4. Выражения с операндами базовых
- •4.1. Автоматическое и явное приведение арифметических типов
- •4.2. Особые ситуации в арифметических выражениях
- •4.3. Логический тип и логические выражения
- •4.4. Выражения с символьными операндами
- •4.5. Тернарная (условная) операция
- •Глава 5. Типы с# как классы платформы .Net
- •5.1. Платформа .Net Framework и спецификация cts
- •5.2. Простые (базовые) типы c# как классы
- •5.3. Специфические методы и поля простых типов
- •Глава 6. Операторы
- •6.1. Общие сведения об операторах
- •6.2. Метки и оператор безусловного перехода
- •6.3. Условный оператор (ветвлений)
- •If (логическое выражение) оператор_1
- •6.4. Операторы цикла
- •6.5. Операторы передачи управления
- •If (условие) break;
- •6.6. Переключатель
- •Int ball; // оценка в баллах:
- •Глава 7. Массивы
- •7.1. Одномерные массивы
- •Int [ ] integers
- •Int number;
- •7.2. Массивы как наследники класса Array
- •7.3. Виды массивов и массивы многомерные
- •Int [,] dots;
- •Int size;
- •7.4. Массивы массивов и непрямоугольные массивы
- •Int size;
- •7.5. Массивы массивов и поверхностное копирование
- •Int size;
- •Int size;
- •Глава 8. Строки – объекты класса string
- •8.1. Строковые литералы
- •8.2. Строковые объекты и ссылки типа string
- •242.ToString()
- •8.3. Операции над строками
- •8.4. Некоторые методы и свойства класса String
- •8.5. Форматирование строк
- •8.6. Строка как контейне
- •8.7. Применение строк в переключателях
- •8.8. Массивы строк
- •8.8. Сравнение строк
- •Int static Compare (string, string)
- •Int static Compare (string, string, Boolean,CultureInfo)
- •If (string.Compare(res, hen, true,
- •8.9. Преобразования с участием строкового типа
- •38 Попугаев.
- •8.10. Аргументы метода Main( )
- •8.11. Неизменяемость объектов класса String
- •Глава 9. Методы c#
- •9.1. Методы–процедуры и методы-функции
- •9.2. Соотношение фиксированных параметров и аргументов
- •Int iPart;
- •9.3. Параметры с типами ссылок
- •Int[ ] temp;
- •Int[ ] temp;
- •9.4. Методы с переменным числом аргументов
- •VarParams(a, b, c);
- •9.5. Перегрузка методов
- •9.6. Рекурсивные методы
- •4*Fact (3); {
- •9.7. Применение метода Array.Sort()
- •Int имя_функции(тип параметр_1, тип параметр_2)
- •If(условие 2) return -1; // порядок соблюдён
- •Глава 10. Класс как совокупность статических
- •10.1. Статические члены класса
- •10.2. Поля классов (статические поля)
- •Int X; // поле объектов класса
- •10.3. Статические константы
- •10.4. Статические методы
- •10.5. Статический конструктор
- •10.6. Статические классы
- •Глава 11. Классы как типы
- •11.1. Объявление класса
- •11.2. Поля объектов
- •11.3. Объявления методов объектов
- •11.4. Пример класса и его объектов
- •Int count; // текущее показание
- •1 ' Counter.Count' is inaccessible due to its protection leve
- •11.5. Ссылка this
- •Int numb;
- •11.6. Конструкторы объектов класса
- •Int p; // порядок - инициализация по умолчанию
- •Void reduce() // Приведение числа к каноническому виду.
- •11.7. Деструкторы и финализаторы
- •Глава 12. Средства взаимодействия с объектами
- •12.1. Принцип инкапсуляции и методы объектов
- •12.2. Свойства классов
- •Internal, private, static, virtual, sealed, override, abstract, extern
- •Internal protected
- •Int p; // инициализация по умолчанию
- •Void reduce() // "Внутренний" для класса метод
- •12.3. Автореализуемые свойств
- •12.4. Индексаторы
- •Int[] days; // часы по дням недели
- •Int search(string str) { // поиск слова
- •12.5. Индексаторы, имитирующие наличие контейнера
- •Глава 13. Включение, вложение и наследование
- •13.1. Включение объектов классов
- •13.2. Вложение классов
- •13.3. Наследование классов
- •13.4. Доступность членов класса при наследовании
- •13.5. Методы при наследовании
- •13.6. Абстрактные методы и абстрактные классы
- •13.7. Опечатанные классы и методы
- •13.8. Применение абстрактых классов
- •Глава 14. Интерфейсы
- •14.1. Два вида наследования в ооп
- •14.2. Объявления интерфейсов
- •Interface имя_интерфейса
- •Interface iPublication { // интерфейс публикаций
- •Void write(); // готовить публикацию
- •Void read(); // читать публикацию
- •14.3. Реализация интерфейсов
- •Interface iPublication { // интерфейс публикаций
- •Void write(); // готовить публикацию
- •Void read(); // читать публикацию
- •Interface iSeries {
- •Void setBegin(); // восстановить начальное состояние
- •Int GetNext { get; } // вернуть очередной член ряда
- •Int this[int k] {get;} // вернуть к-й член ряда
- •Interface iSeries // интерфейс числовых рядов
- •14.4. Интерфейс как ти
- •Interface iGeo { // интерфейс геометрической фигуры
- •Void transform(double coef); // преобразовать размеры
- •Void display(); // вывести характеристики
- •Interface iGeo {
- •Void transform(double coef); // преобразовать размеры
- •Void display(); // вывести характеристики
- •Ira.Transform(3);
- •Ira.Transform(3);
- •14.5. Интерфейсы и наследование
- •Interface iPublication // интерфейс публикаций
- •Interface iBase
- •Interface iBase {
- •Глава 15. Перечисления и структуры
- •15.1. Перечисления
- •15.2. Базовый класс перечислений
- •IsDe fined"
- •15.3. Структуры
- •15.4. Упаковка и распаковка
- •If (obj is Struct1)
- •If (ob is PointS)
- •If (ob is Double)
- •15.5. Реализация структурами интерфейсов
- •Interface iShape {
- •Interface iShape
- •Information(ci);
- •Information(sp);
- •Interface iImage {
- •Void display();
- •Interface iImage
- •Void display();
- •Глава 16. Исключения
- •16.1. О механизме исключений
- •16.3. Свойства исключений
- •16.4. Управление программой с помощью исключений
- •X; // Вводимое число.
- •16.5. Исключения в арифметических выражениях
- •16.6. Генерация исключений
- •If (!double.TryParse(input, out u))
- •If (!double.TryParse(input, out u)
- •16.7. Пользовательские классы исключений
- •Глава 17. Делегаты и события
- •17.1. Синтаксис делегатов
- •17.2. Массивы делегатов
- •Int X, y; // положение робота на плоскости
- •17.3. Многоадресные (групповые) экземпляры делегатов
- •Virtual
- •17.4. Делегаты и обратные вызовы
- •17.5. Анонимные методы
- •17.6. События
- •Int size; // размер массива
- •Int[ ] ar; // ссылка на массив
- •Int temp;
- •Глава 18. Обобщения
- •18.1. Обобщения как средство абстракции
- •18.2. Декларации обобщённых классов "декларация
- •18.3. Ограничения типизирующих параметров
- •Intemface iComparable {
- •Int CompareTo (object p);
- •18.4. Обобщённые структуры "обобщённые структуры"
- •18.5. Обобщённые интерфейсы "обобщённый интерфейс"
- •Int add(t X, t y); // прототип метода
- •18.6. Обобщённые методы "обобщённые методы"
- •18.7. Обобщённые делегаты "обобщённые делегаты"
- •Virtual
- •InnerException
- •Interface
3.6. Переполнения при операциях с целыми
Рассматривая
поразрядные
операции ,
мы
ограничились
операндами
беззнакового типа byte, так как использование знаковых типов требует знакомства с
правилами кодирования отрицательных целых чисел. Переменные и константы типа
byte могут иметь значения от 0 до 255. Соответствующие двоичные коды - 00000000
(все нули) и 11111111 (все единицы). В то же время для знакового типа sbyte
установлены пределы от -128 до +127.
Это связано с принятым на аппаратном уровне правилом кодирования
знаковых целых чисел. Для их внутреннего представления используется так
называемый дополнительный код "дополнительный код" . Если k – количество
разрядов, отведенное для представления числа x (для sbyte k равно 8), то
дополнительный код определяет выражение:
x, если x >=0,
доп (x) =
2k - |x|, если x<0
В битовом представлении чисел с использованием дополнительного кода у
всех положительных чисел самый левый бит равен 0, а у отрицательных – единице.
Минимальное число типа sbyte равно -128. Его двоичный код 10000000. Число
-1 представлено кодом 11111111. Представление нуля 00000000, код единицы
00000001.
Зная правила двоичного кодирования отрицательных целых чисел, легко
понять, как меняется значение переменной знакового типа при поразрядных
операциях. Например, применяя к положительному числу операцию поразрядного
инвертирования ~, мы меняем знак числа и на 1 увеличиваем его абсолютно
е
значение. При поразрядном инвертировании отрицательного числа результат равен
уменьшенному
на
1
его
абсолютному
значению.
Следующая
программа
иллюстрирует применение операции:
//03_05.cs - поразрядное инвертирование знаковых чисел!!!
using System;
class Program
{
static void Main()
{
sbyte sb = 9;
sbyte nb = 3;
Console.WriteLine("~sb = " + ~sb);
Console.WriteLine("~sb+sb = " + (~sb+sb));
Console.WriteLine("~nb = " + ~nb);
Console.WriteLine("~nb+nb = " + (~nb + nb));
}
}
Результат выполнения программы:
~sb = -10
~sb+sb = -1
~nb = -4
~nb+nb = -1
Поразрядный сдвиг "поразрядный сдвиг" влево << целочисленного аргумента
знакового типа может не только изменить его абсолютное значение, но и, зачастую,
изменяет его знак. Приводить примеры здесь нет необходимости. Гораздо важнее
рассмотреть особенности выполнения традиционных арифметических операций над
беззнаковыми и знаковыми операндами с ограниченным количеством разрядов.
Начнем с беззнаковых целочисленных типов. В результате выполнения
следующего фрагмента программы:
byte b=255, c=1, d;
d=(byte)(b+c);
Значением переменной d будет 0. Обоснованность такого результата
иллюстрирует следующее двоичное представление:
11111111 = 255
+
00000001 = 1__
100000000 = 0 (нуль за счет отбрасывания левого разряда
)
Теперь обратимся к операндам знаковых типов, например, типа sbyte.
Если просуммировать числа -1 (с поразрядным представлением 11111111) и 1
(с кодом 00000001), то получим девятиразрядное число с битовым представлением
100000000. Для внутреннего представления чисел типа sbyte отводится 8 разрядов.
Девятиразрядное число в эти рамки не помещается, и левая (старшая) единица
отбрасывается. Тем самым результатом суммирования становится код нуля
00000000. Все совершенно верно – выражение (-1+1) должно быть равно нулю!
Однако, так правильно завершаются вычисления не при всех значениях
целочисленных операндов.
За счет ограниченной разрядности внутреннего представления значений целых
типов при вычислении выражений с целочисленными операндами существует
опасность аварийного выхода результата за пределы разрядной сетки. Например,
после выполнения следующего фрагмента программы:
sbyte x=127, y=127, z;
z=(sbyte) (x+y);
Значением переменной z будет – 2
В этом легко убедиться, представив выполнение операции суммирования в
двоичном виде:
01111111 = 127
+
01111111 = 127
11111110 = - 2 (в дополнительном коде).
Примечание: В операторе z=(sbyte)(x+y); использована операция приведения
типов "приведение типов" (sbyte). При её отсутствии результат суммирования x+y
автоматически приводится к типу int. Попытка присвоить значение типа int
переменной z, имеющей тип sbyte, воспринимается как ошибка, и компиляция
завершается аварийно.
Приведенные
иллюстрации
переполнений
разрядной
сетки
при
арифметических операциях с восьмиразрядными целыми (типов byte, sbyte) могут
быть распространены и на целые типы с большим количеством разрядов (эти типы с
указанием разрядностей приведены в Табл. 2.1).
Основным типом для представления целочисленных данных в C# является ти
п
int. Для представления целочисленных значений типа int используются 32-
разрядные участки памяти. Тем самым предельные значения для значения типа int
таковы:
положительные от 0 до 231-1;
отрицательные от -1 до -231.
В следующей программе результаты умножений переменной типа int на саму
себя выходят за пределы разрядной сетки.
// 03_06.cs - переполнение при целочисленных операндах
using System;
class Program
{
static void Main()
{
int m = 1001;
Console.WriteLine("m = " + m);
Console.WriteLine("m = " + (m = m * m));
Console.WriteLine("m = " + (m = m * m));
Console.WriteLine("m = " + (m = m * m));
}
}
В программе значение целочисленной переменной вначале равной 1001
последовательно умножается само на себя.
Результат выполнения программы:
m = 1001
m = 1002001
m = -1016343263
m = 554036801
После первого умножения m*m значением переменной m становится
100200110, после второго результат выходит за разрядную сетку из 32-х битов.
Левые лишние разряды отбрасываются, однако, оставшийся самый левый 32-й бит
оказывается равным 1, и код воспринимается как представление отрицательного
числа. После следующего умножения 32-й бит оказывается равным 0, и
арифметически неверный результат воспринимается как код положительного числа.
Особо отметим, что исполняющая система никак не реагирует на выход
результата за разрядную сетку, и программисту нужно самостоятельно следить за
возможностью появления таких неверных результатов.
В рассмотренных программах с переменными типов byte и sbyte мы несколько
раз применили операцию преобразования (иначе приведения "приведение типов" )
типов "операция:операция преобразования типов" \y "операция" . Например, были
использованы конструкции:
(byte)(bb&dd)
z=(sbyte)(x+y);
В следующей главе приведение типов будет рассмотрено подробно, а сейчас
покажем его роль в некоторых выражениях с целочисленными операндами.
Поместим в программу операторы:
short dd=15, nn=24;
dd=(dd+nn)/dd;
При компиляции программы будет выведено сообщение об ошибке:
Cannot implicitly convert type ‘int’ to ‘short’.
Невозможно неявное преобразование типа int в short.
Несмотря на то, что в операторах использованы переменные только одного
типа short, в сообщении компилятора указано, что появилось значение типа int!
Компилятор не ошибся – при вычислении выражений с целочисленными
операндами, отличными от типа long, они автоматически приводятся к типу int.
Поэтому результат вычисления (dd+nn)/dd имеет тип int. Для значений типа short
(см. табл. 2.1) выделяется два байта (16 разрядов), значение типа int занимает 4
байта. Попытка присвоить переменной dd с типом short значения типа int
воспринимается компилятором как потенциальный источник ошибки за счёт потери
16-ти старших разрядов числа. Именно поэтому выдано сообщение об ошибке.
Программист может «успокоить» компилятор, применив следующим образом
операцию приведения типов:
dd=(short)((dd+nn)/dd);
При таком присваивании программист берет на себя ответственность за
правильность вычислений.
Обратите внимание на необходимость дополнительных скобок. Если записать
(short)(dd+nn)/dd, то в соответствии с рангами операций к типу short будет
приведено значение (dd+nn), а результат его деления на dd получит тип int.
Контрольные вопросы
Перечислите группы (категории) операций языка C#.
Перечислите названия групп операций в порядке возрастания их приоритетов
(рангов).
Знаки каких бинарных операций могут использоваться в составных операциях
присваивания?
В чём отличия префиксных форм операций декремента и инкремента от
постфиксных.
К каким операциям применимы операции ++ и --?
К каким операндам применима операция %?
К каким операндам применима операция ^?
В чём особенность операции деления целочисленных операндов?
Назовите правила выполнения операций %.
Какому действию эквивалентен сдвиг влево разрядов битового представления
целого числа?
Получите дополнительный код отрицательного числа типа sbyte, модуль которого
не превышает 127.
Объясните механизм возникновения переполнения при вычислениях с
целочисленными операндами.