Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции ВМИиП.docx
Скачиваний:
8
Добавлен:
18.04.2019
Размер:
233 Кб
Скачать
☆

1.3.10. Абстрактные классы

При разработке базового класса часто используются виртуальные функции, которые не выполняют каких-либо действий. Уточнение действий таких произвольных функций производится в производных классах, т.е. эти функции не имеют практической ценности для базового класса. Такие методы называются чисто виртуальными методами, у которых есть декларация о существовании функции, но нет тела функции.

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

Поскольку у чисто виртуального метода нет тела, то создать объект абстрактного класса для данного метода не возможно.

Абстрактные классы не бывают изолированы, они всегда должны быть наследуемыми.

Class vehicle

{

Int wheels;

Float weight;

Public:

Virtual void message(void)=0; // Один пустой метод – абстрактный класс

}; //Чем более полно мы пишем vehicle, тем проще нам программировать в будущем

1.4. Указатели (ссылки). Массивы.

В языке С++ указатель представляет собой особый тип переменной в которой содержится адрес закрепляемого за ним другого объекта программы. Таким объектом может быть сложная структура, в т.ч. экземпляр класса, массив, строка, функция, другой указатель (указатель на другой указатель). Указатель может ссылаться не только на объект программы, но и на любой участок памяти компьютера (который мы в программе не занимали), в т.ч. на область данных BIOS, но переменные типы указателя не может хранить содержимого адреса, она может хранить только адрес.

Указатели предназначены:

  1. Для ссылки на переменные для обработки строк, массивов и на машиных адресов

  2. Для управления памятью при размещении сложных объектов, таких как форма, например, веб-страница

  3. Для передачи и возврата значений параметров функций по ссылке

  4. Для ускорения обработки данных

* [ ] Имя-Переменной-1 [ , Имя-Переменной-2 … ] ;

Примеры:

Int *Per;

Const *Per;

Char *const Per;

Основные операции над указателями (ссылками):

1.4.1 & - операция определения адреса объекта прокраммы:

Int V=3; int* Per; Per=&v;

Per=0

Per=(int *) 1507;

1.4.2. * -оператор разадресации:

Int i=5, j; i=*per;

Int * per= & I ; // Инициализация указатель адресом переменнойi,

Cout << *per<< “ = i записано по адресу “<< per<<endl;

J=per; //это ошибка. Указатель не преобразуется в целое,

J=*per +1; //Переменной j присвоено значение переменной i увеличенное на единицу

per =& j; // переменная реr указывает на адрес переменной

Наследование – это процесс, посредством которого, один объект может наследовать свойства другого объекта и добавлять к ним черты, характерные только для него.

Stdin <stdio.h>

Int fprintf ([указатель-На-Входной-Поток], Управляющая-строка, [,Имя-переменной-1, [Имя-переменной-2…]]);

FILE* ConstChar*

<Conio.h>

Int cprintf (УправляющаяСтрока[,Имя-переменной-1, [Имя-переменной-2…]]);

STDIN – поток стандартного ввода (по умолчанию с клавиатуры)

STDOUT – первый поток стандартного вывода (по умолчании монитор)

STDPRINT - второй поток стандартного вывода (по умолчанию на принтере)

STDERR - потом стандартного вывода сообщений об ошибках на консоль

STDAUX - стандартный дополнительный поток, который может быть прикреплен ко второй консоли, дополнительному порту и т.д.

Лекция 3 от 19.09.2011

На следующем занятии – контрольная!

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

Int * per – переменная является указателем, в которой может содержаться адрес размещения только целого числа

Const * per – указатель содержит ссылки только на такие объекты (переменные), значения которых не меняется в программе

Char * const Per – переменная является указателем на один и тот же адрес памяти, в который можно помещать адреса любых переменных с типом данных char.

Допустимый диапазон значений для любого указателя всегда включается адрес Null и 16-чное число, которое вместе интерпретируется как адрес оперативной памяти.

Операции над указателями:

      1. & - операция определения адреса переменной (объекта программы)

Int V=3; int* Per; Per=&v;

V как просто переменная, р – указатель на целочисленную переменную

Определяем адрес размещения переменной V

Per=0

Указателю присвоили значение 0. Такое присвоение используется для определения достижения конца массива.

Per=(int *) 1507;

Тип данных в скобках долден быть преобразован. Переменной присваивается фактический адрес и уточняется тип данных, который может быть размещен под этим адресом

Операция определения адреса является одноместной (нет второго операнда), имеет максимальный приоритет и имеет ассоциативность справа налево.

      1. *- оператор разадресации служит для определения содержимого, адрес которой содержится в указателе.

Int i=5, j; i=*per;

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

Int * per= & I ; // Инициализация указатель адресом переменнойi,

Cout << *per<< “ = i записано по адресу “<< per<<endl;

J=per; //это ошибка. Указатель не преобразуется в целое

J=*per +1; //Переменной j присвоено значение (записанной по адресу) переменной i увеличенное на единицу

per =& j; // переменная реr указывает на новый адрес переменной

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

Адресная арифметика целесообразна для:

  1. Управления динамическим распределением памяти

  2. Создания и размещения объектов некоего класса в ООП

  3. При работе с файлами, прежде всего с потоковыми функциями доступа к файлам, в которых используется предопределенная структура указателя на поток FILE.

  4. Для передачи определения функции , как объекта, в функцию вызова.

  5. И так далее

Адресная арифметика:

  1. Операция присваивания имеет смысл только для указателей одного и того же типа данных. Благодаря чему указатели будут ссылаться на один и тот же участок памяти.

{ int *pa1, *pa2, I =12345; pa1= & i, pa2=pa1; …}

Если указатели различного типа памяти нужно указать

long = реальный адрес1

  1. Операцию сравнения можно применять, если указатели адресуются на однородные объекты.

{ int * pa1, *pa2;

Int a,b;

Pa1 = & a; pa2 = &b; \\ присваиваются адреса переменных

If(pa1==pa2)

Printf(“Указатели pa1 и pa2 не равны”);

}

  1. К операциям допустимы операции:

Декремента – увеличения

Инкремента – уменьшения

Сложения

Вычитания

Pa1++ Адрес + Sizeof(тип данных)

Pa1- - Адрес - Sizeof(тип данных)

Int n; pa1=pa1+n; Адрес + n*Sizeof(тип данных)

Int m; pa2 = pa2-m; Адрес – n*Sizeof(тип данных)

При работе с массивами операции декремента и инкремента означают переход к ближнему старшему и младшему.

Операции сложения допустимы, если один операнд является указателем, а второй является выражение с типом данных «целое число» ( 5*10 + указатель).

Операция вычитания допустима:

1. Между указателями на объекты одного и того же типа

2. Если левый операнд является указателем, а правый – выражением с типом данных Int

Пример 1:

{ char*pa1,*pa2, b[8];

Pa1= &b[0]; pa2 = & b[6];

Printf(“Количество элементов между двумя адресами %d и %d равно %d\n”, pa2, pa1, (pa2-pa1));

}

Пример 2:

{ char *pa1, *pa2, int b=12, array [12], s=0;

Pa1= & array[0]; pa2 = pa1+b;

For (начальное значение параметра цикла - нам оно не нужно ;(pa2-pa1)>=0;pa1++) //будем крутится пока разница не станет 0

S+= *pa1; // s = s+ какая-то переменная s= s+ *pa1

}

  1. Операция преобразования типа указателя: (Тип данных)*Указатель

  2. При работе с массивами имя массива по умолчанию является указателем (содержит адрес) на его первый элемент

Int *pa1;

Int array[12];

Pa1= & array [0]; // то же pa1 = array

  1. Если указатель ссылается на элементы одного и того же массива, то между ними допустимы операции сравнения:

!=

==

<=

>

>=

>

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

Смотри пример про АГРУМЕНТЫ.

Есть main, которое возвращает значение 1 (return 1;). Есть 3 аргумента. Первый аргумент (целое число) определяет количество фактических аргументов, которые будут переданы в головную функцию MAIN из ОС, увеличенное на единицу.

Например, перед загрузкой БД – сжать ее. Это опция. Открыть БД только для чтения. Открыть БД и сразу задать пароль пользователя БД. И другие аргументы…. А можно запустить а операнд. Сколько передали, сколько опций записали.

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

Схватываем адреса, а окончание строки \0. Как только встретится пробел, значение фактическое закончилось. Распечатываем значение.

Третий аргумент функции MAIN содержит массив указателей на строковые величины, в которых описывается среда выполнения программы.

То есть описание системы, характеристики, пользователи и т.д.

Мы не знаем, сколько описаний есть при загрузке компьютера. У каждого они разные. Не знаем, сколько памяти потребуется.

Массивы:

В языке С массив служит для объедения в одном объекте программы группы элементов одного и того же типа. Т.к. в стандарте С нет типа данных «строка», то массив заменяется «массивом символов».

Массив С++ представляет собой специальную форму указателя, связанную с непрерывным фрагментом памяти.

Объявление массива в стандарте С++ всегда связано с выделением ему оперативной памяти. Поэтому не допускается использование динамических массивов.

Формат объявления массива:

Тип-Данных Имя-Массива [Константное-Выражение[={Инициализация}]];

Или

Тип-Данных Имя-Массива [] = {Инициализация};

При объявлении массива его можно сразу инициализировать. В качестве инициализации может стоять выражение. Объявить можно и без указания его размера с пустыми [].

Количество элементов массива определяется либо

  1. целочисленным константным выражением

  2. при его отсутствии количеством инициализаторов

  3. либо количеством элементов (константным выражением) другого массива, на который ссылается массив

# include <io stream.h>

Const int SIZE= 3;

Void main(void)

{int a[SIZE]; //выделена память под 3 элемента а[0], a[1],a [2].

For{i=0; I <SIZE; ++ i}

{ a[i]=i*i;; const << “a {<<i<<’}=”<<a[i]<<””\t”;

Sum +=a[i];}

Count <<”\n sum = “ <<sum<< end};

}

Пример

INT ARRAY {2}{3};

CHAR S[]= «это массив «}* Данный массив будет представлят собой {} – элементов, последний из которых будт иметь значение «/0»

INT ARRAY [2][3] = {1,2} {4}}; /* Получи следующее: (задали размерность массива)

  1. 2 0

4 0 0

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

Момент объявления sixe уже определено. Выделена память под 3 элемента. Суммируем значения и выводим. Последнему элементу массива по умолчанию присваивается значние /0.

/0 – используется, чтобы понять, когда кончился элемент.

Не допускается, чтобы массив имел отложенный тип данных void.

Замечание. Если количество инциализаторов меньше, чем объявлено элементов массива явным образом, то неопределенным элементам справа налево по умолчанию присваивается значение 0.

Последним элементом в данном массиве будет иметь значение m, /0 бдудет потерян.

Замечание. Если инциализирующая стркоа символов окажется длиннее заданной явным образом длины массива, то лишние символы справа налево отбрасыватся вместе с символом /0.

Замечание 3. Если количество инициализаторов превосходит количество элементов массива чисел то будет сгенерирована ошибка.

При объявлении массива с типом данных UNION первый элемент массива обязательно должен бывьб инициализирован.

Замечаниае 4. Т.к. при работе с элементами массива в оперативной памяти без разрыва между ними, то при работе с массивами необходимо использовать адресную арифметику

CHAR S[5] = «это массив» /* Последний элемент, с индексом равным четырем, будет иметь значение

А) Сначала I умножается на размер типа данных массива, таким образом вычисляется величина смещения отосительно начало массива:

I* SIZEOF(Тип Данных)

Б) Затем определяется новый адрес, когда величина смещенная складывается с адресом первого элемента массива: Новый-Адрес=Базавый-Адрес+I *SIZEOF(Тип Данных)

Базовый адрес это адрес первого элемента массива, который выдает компилятор при объявлении массива.

В)в заключении производится операция разадрсации:

*Новый-Адрес

INT ARRAY[20]; // Выделена память

INT *p, l=10

VOID Print (INT *, INT) // Объявления прототипа функции, то как ее определение находится ниже, после точки вызова

…

Print(p, l); // Вызов функции печати

…

VOID Print (INT *K, NT M);

{

INT *R=K+M; WHILE((R-k)>=0)

{ COUT<<*K,K++; // Разадресация, увеличиваю адрес на 1

RETURN;

}

}

В этом примере мы написали функцию принт обработки массива с заранее неизвестным количеством элементов.

Смотри пример лр1. Там двумерный массив. Ему выделяется память только в том случае, когда введем ему количество строк и столбцов.

Двумерную матрицу, которая представляет собой массив массивов, мы можем объявить двойным указателем. По сути это означает, что массив MATRIX содержит элементы, которые в свою очередь являются массивами.

FLOAT ** MATRIX;

INT SUM(INTA[], INT M) //в функцию передаем указатель на начало массива и 1 символ

{ INT I, S=0;

FOR (I=0; I<M; ++I)

S+=A[I];

RETURN (S);

}

STRUCT My_Type

{DOUBLE ** My_Base: Int Row_Size, Column_Size;}

    1. Обработка исключительных ситуаций.

(Вышлет его)

    1. Препроцессор

Несколько функций, вся работа через адреса, не должно быть заранее определено кол-во строк и колонок.

Лекция 4 от 26.09.2011

1.6 Препроцессор (раздел 1.5???)

Работа препроцессора происходит перед компиляцией С-программы. И заключается в основном в подстановке текста взамен встречаемых ключевых слов. Препроцессор представляет собой не часть компилятора, но начальную часть процесса компиляции. Указания препроцессора всегда начинаются с символа # и могут находится в любом месте программы.

Основное назначение:

  1. Разработка инструментария для создания сложных программных проектов, состоящих из несколько программных файлов, библиотек, овер-леев и так далее. Проект развивает такие принципы ООП, как принцип инкапсуляции (скрытие информации) и принцип модульности в виде динамического или статистического связывания объектов.

  2. Препроцессор позволяет создать общедоступные символьные константы и макросы

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

  4. Препроцессор позволяет управлять режимами условной компиляции программного кода и условного выполнения директив самого препроцессора.

Основные действия:

  1. Включение в компилируемый файл фрагментов других файлов

  2. О

    Компиляция

    пределение символических констант и макросов

  3. Управление условной компиляцией

Вставляемые *.срр

Промежуточный *.obj

Исходная *.с (срр)

Исходная *.с (срр) + Подстановки

Компиляция

Вставляемые *.h (hрр)

Файл определений *.def

Файл ресурсов *.rc

Исполняемый файл *.exe

Динамически подключаемая библиотека *.dll

Библиотечный файл *.lib

Могут быть созданы 3 типа файлов:

  1. Исполняемый (*.exe)

  2. Библиотечный

  3. Диалект (динамически присоединенная библиотека)