Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Условная компиляция






Директивы препроцессора # if, # else, # endif и # elif позволяют, в зависимости от результатов проверки некоторых условий, включать в программу один из нескольких вариантов текста:

# if препроцессорное_условие

текст 1

# else

текст 2

# endif

дальнейший текст.

Условие -- это константное выражение, которое строится из макроимен, констант и знаков операций, включая логические связки & & и | |. Допускается также выражение sizeof (имя_типа) и препроцессорная функция defined(макроимя), возвращающая 1, если это макроимя определено, и 0, если оно не определено. Вместо директивы

# if defined(DEBUG)

можно написать

# ifdef DEBUG

а вместо

# if! defined(DEBUG)

написать

# ifndef DEBUG

Комбинации #if - #else могут быть вложенными, причем последовательность #else - #if заменяется одной директивой #elif с условием:

# if препроцессорное_условие_1

текст 1

# elif препроцессорное_условие_2

текст_2

# else

текст_3

# endif

В файлах заголовков для предотвращения многократного включения одного и того же заголовка в программу обычно присутствует текст вида:

#if! defined(_ _DEFS_H)

#define _ _DEFS_H

/* Текст объявляемых заголовков */

.......................................

#endif /* Конец _ _DEFS_H */

ДИНАМИЧЕСКАЯ ПАМЯТЬ

Вторым способом хранения информации служит использование системы динамического выде­ления памяти Borland С++. В этом методе память для хранения информации выделяется из сво­бодной области памяти по мере надобности и возвращается назад, т.е. освобождается, когда надобность в ней исчезла. Область свободной памяти лежит между областью памяти, где разме­щается программа, и стеком. Эта область называется кучей (heap) и используется для запросов на динамическое выделение памяти.

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

Доступ к динамической памяти возможен только через указатели, т. е. нельзя создавать в неё переменные, но можно выделять её фрагменты и связывать из с некоторым указателем.

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

Для этого вам необходимо знать всего два оператора:

· new - выделение памяти, если выделение памяти не произошло возвращается нулевой указатель;

· delete - освобождение памяти, не во всех компиляторах после освобождения памяти указателю присваивается 0.

 

#include < iostream> using namespace std; int main() {// создание объекта типа int со значением 45// и сохранение его адреса в указателе obj int* obj = new int(45); // освободили память на которую указывал objcout< < " *obj=" < < *obj< < endl; delete obj; // елементы массива нельзя инициализировать// им задается значение по умолчанию// в случае классов вызывается конструктор по умолчаниюint* array = new int[10]; cout< < " array: "; for(unsigned int i=0; i< 10; i++) cout< < array[i]< < " "; cout< < endl; delete [] array; // для избежания возможных ошибок// указателю лучше присвоить 0 (при доступе // к нулевому указателю генерируется системная ошибка, // а значит ошибка не останется незамеченной)array=0;...}

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

int* p; p = new int; *p = 10; cout < < *p; // 10delete p; // память освобождена

 

Если не освобождать динамическую память, то она будет занята до завершения программы, что неприемлемо.

При выделении одной динамической переменной (одной ячейки памяти), можно сразу инициализировать её значение:

int* p; p = new int(10); cout < < *p; // 10delete p; // память освобождена

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

Для этого его размер указывается в квадратных скобках после типа.

Чтобы удалить динамический массив и освободить память используется оператор delete[].

int* p; p = new int[13]; for (int i=0; i< 13; i++) { *(p+i) = i + 1; cout < < *(p+i) < < ' '; // 1 2 3... 13}delete[] p; // память освобождена, из неё удалены все элементы

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

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

int* p; p = new int(13); int a = 666; p = & a; // теперь до 13 никак не добраться

 

Проблема становится особенно острой, когда в памяти теряются целые массивы (они занимают больше места, чем отдельные переменные).

int* p; for (int i=1; i< =10; i++) { p = new int[100]; }delete[] p;

На каждом шаге цикла создаётся динамический массив из 100 элементов. Всего таких массивов будет создано 10, но только от последнего из них память будет освобождена после выхода из цикла. 9 массивов продолжат занимать место в памяти до конца программы. 9 массивов * 100 элементов * 4 байта = 3600 байт потерянной памяти, которую никак нельзя использовать (ни в этой программе, не в других запущенных).

Очень важно после использования динамической памяти не забывать освобождать её в нужный момент!

1 2 int * bobby; bobby = new int [5];

 

В этом случае система динамически присваивает пространство для пяти элементов типа int и возвращает указатель на первый элемент последовательности, которая присваивается bobby. Поэтому, теперь, bobby указывает на допустимый блок памяти с пространством для пяти элементов типа на int.

К первому элементу, на который указывает bobby, можно получить доступ или с прессованием bobby[0] или с прессованием *bobby. Оба эквивалентны, как был объяснен в разделе об указателях. К второму элементу можно получить доступ или с bobby[1] или с *(bobby+1) и так далее.

 

ООП

Однако к концу 1980-х годов слишком очевидными стали некоторые его недостатки. К сожалению, структурное программирование отделяет структуры данных от функций, управляющих ими. Кроме того, в структурном программировании полностью отсутствуют встроенные способы связи данных с функциями. Программисты обнаружили, что возможность многократного использования стандартных блоков, повторяющихся во многих программах, вполне естественна. Однако функции, которые прекрасно работали с одним типом данных, зачастую не могли воспользоваться другими типами, что ограничивало их преимущества. Вследствие этого была разработана новая концепция объектно-ориентированного программирования.

 

Суть объектно-ориентированного программирования заключается в использовании «объектов», т.е. скорее образов, чем «данных». Объекты объединяются в классы, причем любой программист может создавать собственные классы. Например, можно создать класс «Животные», или «Механизмы», или «Средства передвижения». Каждый конкретнй класс имеет собственные функции (методы) и собственные переменные. Некоторые переменные (члены класса) могут быть защищены от прямого доступа из внешней программы

Объектно-ориентированное программирование (ООП) — подход к программированию, при котором основными концепциями являются понятия объектов и классов.

Класс — это определяемый разработчиком тип данных.

Тип данных характеризуется:

1. Способом хранения и представления этих данных.

2. Назначением этих данных (профилем их использование).

3. Набором действий, которые над этими данными могут производится.

Например, тип int предназначен для хранения целых чисел и подразумевает ряд операция над ними (+, -, *, /, % и пр.).

Класс — это тип, описывающий устройство объектов, их поведение и способ представления.

Объект — сущность обладающая определённым поведением и способом представления, т. е. относящееся к классу (говорят, что объект — это экземпляр класса, если он к нему относится).

Описание класса начинается со служебного слова class, вслед за которым указывается имя класса. Затем в блоке следует описание класса и после закрывающей скобки блока ставится точка с запятой.

Описание класса состоит из полей и методов.

Поля (или свойства, в рамках C++ это можно считать синонимом) описывают то, какие данные смогут хранить экземпляры класса (т.е. объекты). Конкретные значения сохраняются уже внутри объектов. Поля объявляются в теле класса.

К полям внутри класса можно обращаться непосредственно по именам полей.

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

Методы объявляются в теле класса. Описываться могут там же, но могут и за пределами класса (внутри класса в таком случае достаточно представить прототип метода, а за пределами класса определять метод поставив перед его именем — имя класса и оператор::).

Пример:

class Complex { double img; double real; };

В примере описан класс Complex с двумя полями img и real.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.