ПОЗНАВАТЕЛЬНОЕ Сила воли ведет к действию, а позитивные действия формируют позитивное отношение Как определить диапазон голоса - ваш вокал
Игровые автоматы с быстрым выводом Как цель узнает о ваших желаниях прежде, чем вы начнете действовать. Как компании прогнозируют привычки и манипулируют ими Целительная привычка Как самому избавиться от обидчивости Противоречивые взгляды на качества, присущие мужчинам Тренинг уверенности в себе Вкуснейший "Салат из свеклы с чесноком" Натюрморт и его изобразительные возможности Применение, как принимать мумие? Мумие для волос, лица, при переломах, при кровотечении и т.д. Как научиться брать на себя ответственность Зачем нужны границы в отношениях с детьми? Световозвращающие элементы на детской одежде Как победить свой возраст? Восемь уникальных способов, которые помогут достичь долголетия Как слышать голос Бога Классификация ожирения по ИМТ (ВОЗ) Глава 3. Завет мужчины с женщиной 
Оси и плоскости тела человека - Тело человека состоит из определенных топографических частей и участков, в которых расположены органы, мышцы, сосуды, нервы и т.д. Отёска стен и прирубка косяков - Когда на доме не достаёт окон и дверей, красивое высокое крыльцо ещё только в воображении, приходится подниматься с улицы в дом по трапу. Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) - В простых моделях рынка спрос и предложение обычно полагают зависящими только от текущей цены на товар. | Предикаты, функторы и адаптеры Программирование. · Динамические структуры в языке Pascal. Статические и динамические переменные. Указатели. Типизированный указатель. Операция разыменования. Стандартные процедуры для работы с памятью. Использование указателей. Связанные списки. Основные типы связанных списков стек и очередь, линейные и циклические связанные списки. Данные динамической структуры – это данные, внутреннее строение которых формируется по какому-либо закону, но количество элементов, их взаиморасположение и взаимосвязи могут динамически изменяться во время выполнения программы, согласно закону формирования.  Данные динамической структуры: К данным динамической структуры относят файлы, несвязанные и связанные динамические данные. Заметим, что файлы в данной классификации отнесены к динамическим структурам данных. Это сделано исходя из вышеприведенного определения. Хотя удаление и вставка элементов в середину файла не допускается, зато длина файла в процессе работы программы может изменяться – увеличиваться или уменьшаться до нуля. А это уже динамическое свойство файла как структуры данных. Все переменные, используемые в программе, размещаются в памяти согласно вполне определенным правилам: для локальных переменных память отводится при вызове подпрограммы; при выходе из нее эта память освобождается, а сами переменные прекращают существовать; глобальным переменным память отводится в начале выполнения программы; эти переменные существуют в течение всего периода работы программы. Таким образом, распределение памяти во всех этих случаях производится полностью автоматически и подчинено стековой дисциплине. Переменные, память, под которые распределяется описанным образом, называются статическими. Кроме этого язык программирования Pascal дает возможность образовать новые переменные в любой момент работы программы без учета ее статической структуры, сообразуясь с потребностями решаемой задачи. Точно так же допускается уничтожение созданных переменных в произвольный момент выполнения программы. Переменные, созданием и уничтожением которых явно может управлять программист, называются динамическими переменными. Указатель - это ссылка на данные или код вашей программы. Он представляет адрес в памяти элемента, на который указывает. Ис- пользование указателей позволяет писать большие и более гибкие программы Рано или поздно каждый программист, работающий на Паскале, попадает в ситуацию, требующую использования указателей. Указате- ли требуется применять в следующих случаях: * Если ваша программа работает с большими объемами данных (общий объем которых превышает 64К). * Если ваша программа во время компиляция использует данные неизвестного размера. * Если программа использует временные буферы данных. * Если ваша программа работает с несколькими типами данных. * Если ваша программа использует связанные списки данных или объектов.var SomeNumber: Integer; SomeAddress: Pointer; begin SomeNumber := 17; {присвоить SomeNumber значение} SomeAddress := @SomeNumber; {присвоить SomeAddress адрес} SomeAddress := Addr(SomeNumber); {другой способ получения адреса} end. Типизированные указатели Чтобы определить типизированный указатель, вы можете описать новый тип, определенный символом каре (^), за которым следуют один или более идентификаторов. Например, чтобы определить указатель на Integer, вы можете сделать следующее: type PIneger = ^Integer; Теперь вы можете описать переменные типа PInteger. Если вы не собираетесь часто использовать ссылочный тип, то можете просто описать переменные, как указатели на уже определенный тип. Например, если вы определили PInteger как ^Integer, то следующие переменной эквивалентны: var X: ^Integer: Y: PInteger; Разыменование указателей Разыменовав типизированный указатель, вы можете интерпретировать так, как если бы это была переменная типа, на которую он указывает. Чтобы разыменовать указатель, поместите символ каре (^) после идентификатора указателя. Ниже показаны некоторые примеры разыменования указателя: type PInteger = ^Integer; var SomeNumber: Integer; { присвоить SomeNumber 17 } SomeAddress := @SomeNumber; { SomeAddress указывает на SomeNumber } Writeln(SomeNumber); { напечатать 17 } Writeln(SomeAddress); { не допускается; указатели печатать нельзя } Writeln(SomeAddress^); { напечатать 17 } AnotherAddress := SomeAddress; { также указывает на SomeNumber } AnotehrAddress^ := 99; { новое значение для SomeNumber } Writeln(SomeNumber); { напечатать 99 } end.Процедуры динамического распределения памяти -------------------T-------------------------------------------- ¦ Процедура/функция¦ Описание ¦ +------------------+--------------------------------------------+ ¦ Dispose ¦ Уничтожает динамическую переменную. ¦ +------------------+--------------------------------------------+ ¦ FrееМем ¦ Уничтожает динамическую переменную данного¦ ¦ ¦ размера. ¦ +------------------+--------------------------------------------+ ¦ GetМем ¦ Создает новую динамическую переменную за-¦ ¦ ¦ данного размера и устанавливает на нее пе-¦ ¦ ¦ ременную-указатель. ¦ +------------------+--------------------------------------------+ ¦ МахАvail ¦ Возвращает размер наибольшего непрерывного¦ ¦ ¦ свободного модуля в динамически распределя-¦ ¦ ¦ емой области памяти, соответствующий разме-¦ ¦ ¦ ру наибольшей динамической переменной, ко-¦ ¦ ¦ торая может быть выделена при обращении в¦ ¦ ¦ МахAvail. ¦ +------------------+--------------------------------------------+ ¦ МемАvail ¦ Возвращает количество имеющихся в динами-¦ ¦ ¦ чески распределяемой области свободных¦ ¦ ¦ байт. ¦ +------------------+--------------------------------------------+ ¦ New ¦ Создает новую динамическую переменную и ус-¦ ¦ ¦ танавливает на нее переменную-указатель. ¦ L------------------+---------------------------------------------Ниже перечислены функции для работы с указателями и адреса- ми. -------------------T-------------------------------------------- ¦ Функции ¦ Описание ¦ +------------------+--------------------------------------------+ ¦ Аddr ¦ Возвращает адрес заданного объекта. ¦ +------------------+--------------------------------------------+ ¦ CSeg ¦ Возвращает текущее значение регистра CS. ¦ +------------------+--------------------------------------------+ ¦ DSeg ¦ Возвращает текущее значение регистра DS. ¦ +------------------+--------------------------------------------+ ¦ Оfs ¦ Возвращает смещение для заданного объекта. ¦ +------------------+--------------------------------------------+ ¦ Ptr ¦ Преобразует адрес базового сегмента и сме-¦ ¦ ¦ щение в значение типа указатель. ¦ +------------------+--------------------------------------------+ ¦ Seg ¦ Возвращает сегмент для заданного объекта. ¦ +------------------+--------------------------------------------+ ¦ SPtr ¦ Возвращает текущее значение регистра SР. ¦ +------------------+--------------------------------------------+ ¦ SSeg ¦ Возвращает текущее значение регистра SS. ¦ L------------------+--------------------------------------------- Использование указателей * Распределение динамических переменных. * Освобождение выделенной для динамических переменных памяти. * Распределение и освобождение выделенных объемов памяти. * Проверка доступного в динамически распределяемой области пространства. Связанный список - это набор последовательно организованных данных. Главное преимущество связанных списков перед массивами состоит в том, что они могут уменьшать или увеличивать свои размеры во время выполнения программы. В частности, мы не должны заранее знать его максимальный размер. Стек – это линейный список, в котором добавление новых элементов и удаление существующих производится только с одного конца, называемого вершиной стека. При программировании на Паскале стек чаще всего реализуется в виде однонаправленного списка. Каждый элемент структуры содержит указатель на следующий. Однако, к этому виду списка, по определению, неприменима операция обхода элементов. Доступ возможен только к верхнему элементу структуры. Стек предполагает вставку и удаление элементов, поэтому он является динамической, постоянно меняющейся структурой. Очередь – линейный список, элементы в который добавляются только в конец, а исключаются из начала. · Язык программирования С. Структура и достоинства языка. Простые и составные типы. Типы данных. Определение размеров памяти для хранения данных. Константы целые, вещественные, символьные и строковые. Специальные управляющие символьные константы. Описания с начальным присваиванием. C — компилируемый статически типизированный язык программирования общего назначения. Первоначально был разработан для реализации операционной системы UNIX, но, впоследствии, был перенесён на множество других платформ. Согласно дизайну языка Си, его конструкции близко сопоставляются типичным машинным инструкциям, благодаря чему он нашёл применение в проектах, для которых был свойственен язык ассемблера, в том числе как в операционных системах, так и в различном прикладном ПО для множества устройств — от суперкомпьютеров до встраиваемых систем. Язык программирования Си оказал существенное влияние на развитие индустрии программного обеспечения, а его синтаксис стал основой для таких языков программирования, как C++, C#, Java и Objective-C. Язык Си уникален с той точки зрения, что именно он стал первым языком высокого уровня, всерьёз потеснившим ассемблер в разработке системного программного обеспечения. Он остаётся языком, реализованным на максимальном количестве аппаратных платформ, и одним из самых популярных языков программирования, особенно в мире свободного программного обеспечения Си предлагает следующие важные особенности: - простую языковую базу, из которой вынесены в библиотеки многие существенные возможности, вроде математических функций или функций управления файлами;
- ориентацию на процедурное программирование, обеспечивающую удобство применения структурного стиля программирования;
- систему типов, предохраняющую от бессмысленных операций;
- использование препроцессора для, например, определения макросов и включения файлов с исходным кодом;
- непосредственный доступ к памяти компьютера через использование указателей;
- минимальное число ключевых слов;
- передачу параметров в функцию по значению, а не по ссылке (при этом передача по ссылке эмулируется с помощью указателей);
- указатели на функции и статические переменные;
- области действия имён;
- структуры и объединения — определяемые пользователем собирательные типы данных, которыми можно манипулировать как одним целым;
- средства объектно-ориентированного программирования[6];
В то же время в Си отсутствуют - вложенные функции;
- сопрограммы;
Типы Система типов в Си подобна типам в других потомках Алгола, таких, как Паскаль. В Си имеются типы целых чисел различных размеров (short int, long int), со знаком (signed) и без (unsigned), чисел с плавающей запятой (float, double), символов, перечисляемых типов (enum) и записей-структур (struct). Кроме того, язык Си предлагает тип объединение (union), с помощью которого можно осуществлять каламбуры типизации — либо хранить в одном месте памяти разнородные данные, не пересекающиеся по времени существования (это позволяет экономить память), либо обращаться к содержимому участка памяти, как к данным разных типов (что позволяет менять тип-интерпретацию данных, не меняя сами данные). В Си есть три разных способа выделения памяти (классы памяти) для объектов: - Статическое выделение памяти: пространство для объектов создаётся в сегменте данных программы в момент компиляции; время жизни таких объектов совпадает со временем жизни этого кода. Изменение таких объектов ведёт к так называемому в стандарте «неопределённому поведению» (англ. undefined behaviour). На практике эта операция приводит к ошибке во время выполнения.
- Автоматическое выделение памяти: объекты можно хранить в стеке; эта память затем автоматически освобождается и может быть использована снова, после того, как программа выходит из блока, использующего его.
- Динамическое выделение памяти: блоки памяти нужного размера могут запрашиваться во время выполнения программы с помощью библиотечных функций malloc, realloc, calloc из области памяти, называемой кучей. Эти блоки освобождаются и могут быть использованы снова после вызова для них функции free.
Целочисленные константы Целочисленные данные в языке Си могут быть представлены в одной из следующих систем счисления: Десятичные | Последовательность цифр (0 — 9), которая начинаются с цифры, отличной от нуля. Пример: 1, -29, 385. Исключение — число 0. | Восьмеричные | Последовательность цифр (0 — 7), которая всегда начинается с 0. Пример: 00, 071, -052, -03. | Шестнадцатеричные | Последовательность шестнадцатеричных цифр (0 — 9 и A — F), которой предшествует присутствует 0x. Пример: 0x0, 0x1, -0x2AF, 0x17. | Вещественные константы Константа с плавающей точкой (вещественная константа) всегда представляется числом с плавающей точкой двойной точности, т. е. как имеющая тип double, и состоит из следующих частей: - целой части — последовательности цифр;
- точки - разделителя целой и дробной части;
- дробной части — последовательности цифр;
- символа экспоненты е или E;
- экспоненты в виде целой константы (может быть со знаком).
Любая часть (но не обе сразу) из нижеследующих пар может быть опущена: - целая или дробная часть;
- точка или символ е (Е) и экспонента в виде целой константы.
Символьные константы Символьная константа — это один символ, например: 'z'. В качестве символьных констант также могут использоваться управляющие коды, не имеющие графического представления. При этом код управляющего символа начинается с символа '\' (обратный слеш). Код | Обозначение | Описание | 0x00 | '\0' | Нуль-символ, NULL | 0x07 | '\a' | Звуковой сигнал. | 0x08 | '\b' | Возврат на 1 шаг (Backspace) | 0x09 | '\t' | Горизонтальная табуляция (Tab) | 0x0A | '\n' | Перевод строки (Enter) | 0x0B | '\v' | Вертикальная табуляция (в консоли аналогична переводу строки) | 0x0C | '\f' | Смена страницы | 0x0D | '\r' | Возврат каретки | Строковые константы Строковая константа — это последовательность символов, заключенная в кавычки, например: "Это строковая константа" Кавычки не входят в строку, а лишь ограничивают её. Технически строковая константа представляет собой массив символов, и по этому признаку может быть отнесена к разряду сложных объектов языка Си. В конце каждой строковой константы компилятор помещает '\0' (нуль-символ), чтобы программе было возможно определить конец строки. Такое представление означает, что размер строковой константы не ограничен каким-либо пределом, но для определения длины строковой константы её нужно полностью просмотреть. · Абстрактные классы в С++. Абстрактные классы используются в качестве обобщенных концепций, на основе которых можно создавать более конкретные производные классы.Невозможно создать объект типа абстрактного класса; однако можно использовать указатели и ссылки на типы абстрактного класса. Класс, содержащий хотя бы одну чисто виртуальную функцию, считается абстрактным. Классы, производные от абстрактного класса, должны реализовать все его чисто виртуальные функции, иначе они также будут абстрактными классами. Виртуальная функция объявляется как "чистая" с помощью синтаксиса спецификатора-чистоты (рассмотренного в разделе Реализация протокола класса).Рассмотрим пример, представленный в разделе Виртуальные функции.Класс Account создан для того, чтобы предоставлять общие функции, но объекты типа Account имеют слишком общий характер для практического применения.Таким образом, класс Account является хорошим кандидатом в абстрактный класс: // deriv_AbstractClasses.cpp// compile with: /LDclass Account {public: Account( double d ); // Constructor. virtual double GetBalance(); // Obtain balance. virtual void PrintBalance() = 0; // Pure virtual function.private: double _balance;}; Единственное различие между этим и предыдущим объявлениями состоит в том, что функция PrintBalance объявлена со спецификатором чисто виртуальной функции pure (= 0). Абстрактные классы невозможно использовать для следующих элементов: - переменных и данных членов;
- типов аргументов;
- типов возвращаемых функциями значений;
- типов явных преобразований.
· Проявления полиморфизма в программах на С++. Полиморфизм (polymorphism) (от греческого polymorphos) - это свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Целью полиморфизма, применительно к объектно-ориентированному программированию, является использование одного имени для задания общих для класса действий. Выполнение каждого конкретного действия будет определяться типом данных. Например для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует трёх различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В С++ каждая из этих функций может быть названа abs(). Тип данных, который используется при вызове функции, определяет, какая конкретная версия функции действительно выполняется. В С++ можно использовать одно имя функции для множества различных действий. Это называется перегрузкой функций (function overloading). В более общем смысле, концепцией полиморфизма является идея "один интерфейс, множество методов". Это означает, что можно создать общий интерфейс для группы близких по смыслу действий. Преимуществом полиморфизма является то, что он помогает мнижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий. Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор. Вам, как программисту, не нужно делать этот выбор самому. Нужно только помнить и использовать общий интерфейс. Пример из предыдущего абзаца показывает, как, имея три имени для функции определения абсолютной величины числа вместо одного, обычная задача становится более сложной, чем это действительно необходимо. Полиморфизм может применяться также и к операторам. Фактически во всех языках программирования ограниченно применяется полиморфизм, например, в арифметических операторах. Так, в Си, символ + используется для складывания целых, длинных целых, символьных переменных и чисел с плавающей точкой. В этом случае компилятор автоматически определяет, какой тип арифметики требуется. В С++ вы можете применить эту концепцию и к другим, заданным вами, типам данных. Такой тип полиморфизма называется перегрузкой операторов (operator overloading). Ключевым в понимании полиморфизма является то, что он позволяет вам манипулировать объектами различной степени сложности путём создания общего для них стандартного интерфейса для реализации похожих действий. · Инкапсуляция и наследование. Инкапсуляция (encapsulation) - это механизм, который объединяет данные и код, манипулирующий зтими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создаётся так называемый "чёрный ящик". Когда коды и данные объединяются таким способом, создаётся объект (object). Другими словами, объект - это то, что поддерживает инкапсуляцию. Внутри объекта коды и данные могут быть закрытыми (private). Закрытые коды или данные доступны только для других частей этого объекта. Таким образом, закрытые коды и данные недоступны для тех частей программы, которые существуют вне объекта. Если коды и данные являются открытыми, то, несмотря на то, что они заданы внутри объекта, они доступны и для других частей программы. Характерной является ситуация, когда открытая часть объекта используется для того, чтобы обеспечить контролируемый интерфейс закрытых элементов объекта. На самом деле объект является переменной определённого пользователем типа. Может показаться странным, что объект, который объединяет коды и данные, можно рассматривать как переменную. Однако применительно к объектно-ориентированному программированию это именно так. Каждый элемент данных такого типа является составной переменной. Наследование (inheritance) - это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него. Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации. Например, подумайте об описании жилого дома. Дом - это часть общего класса, называемого строением. С другой стороны, строение - это часть более общего класса - конструкции, который является частью ещё более общего класса объектов, который можно назвать созданием рук человека. В каждом случае порождённый класс наследует все, связанные с родителем, качества и добавляет к ним свои собственные определяющие характеристики. Без использования иерархии классов, для каждого объекта пришлось бы задать все характеристики, которые бы исчерпывающи его определяли. Однако при использовании наследования можно описать объект путём определения того общего класса (или классов), к которому он относится, с теми специальными чертами, которые делают объект уникальным. Наследование играет очень важную роль в OOP. · Виртуальные методы в С++. Виртуальный метод (виртуальная функция) — в объектно-ориентированном программировании метод (функция) класса, который может быть переопределён в классах-наследниках так, что конкретная реализация метода для вызова будет определяться во время исполнения. Таким образом, программисту необязательно знать точный тип объекта для работы с ним через виртуальные методы: достаточно лишь знать, что объект принадлежит классу или наследнику класса, в котором метод объявлен. Виртуальные методы — один из важнейших приёмов реализации полиморфизма. Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа. Одни языки программирования (например, C++, C#) требуют явно указывать, что данный метод является виртуальным. Пример на C++, иллюстрирующий отличие виртуальных функций от невиртуальных: Предположим, базовый класс Animal (животное) может иметь виртуальный метод eat (кушать). Подкласс (класс-потомок) Fish (рыба) переопределит метод eat() не так как его переопределит подкласс Wolf (волк), но можно вызвать eat() на любом экземпляре класса, унаследованного от класса Animal, и получить поведение eat(), соответствующее данному подклассу. class Animal {public: void /*невиртуальный*/ move(void) { std::cout << "This animal moves in some way" << std::endl; } virtual void eat(void) {}}; // Класс "Animal" может обладать определением метода eat() при необходимости.class Llama : public Animal {public: // Невиртуальный метод move(), унаследован, но не переопределён void eat(void) { std::cout << "Llamas eat grass!" << std::endl; }}; Это позволяет программисту обрабатывать список объектов класса Animal, вызывая над каждым объектом метод eat(), не задумываясь о том к какому подклассу принадлежит текущий объект (то есть как питается конкретное животное). · Статические методы и свойства класса в С++. Статический метод может работать со статическими переменными класса и с объектами класса. Он может выполнять какие-то действия общие для всех объектов данного класса или для указываемой группы объектов, изменение общих параметров, что-то вроде сборки мусора и т.д. - Переменные внутри метода не обязательно будут static.
- Создание и уничтожение экземпляров класса никак не затронет статический метод, его можно вызывать независимо от существования объектов класса. Это аналог обычной функции, только имя у неё необычное и область видимости.
- Существование статического метода никак не отражается на том, как будет храниться объект класса.
· Области видимости переменных и членов класса в С++. Область видимости объекта (переменной или функции) определяет, в каких участках программы допустимо использование имени этого объекта. Область видимости имени начинается в точке объявления, точнее, сразу после объявителя, но перед инициализатором. Поэтому допускается использование имени в качестве инициализирующего значения для себя самого. Глобальные переменные Переменная, объявленная на внешнем уровне, имеет глобальное время жизни. При отсутствии инициализатора такая переменная инициализируется нулевым значением. Область видимости переменной, определенной на внешнем уровне, распространяется от точки, где она определена, до конца исходного файла. Переменная недоступна выше своего определения в том же самом исходном файле. На другие исходные файлы программы область видимости переменной может быть распространена только в том случае, если ее определение не содержит спецификации класса памяти static. Если в объявлении переменной задана спецификация класса памяти static, то в других исходных файлах могут быть определены другие переменные с тем же именем и любым классом памяти. Эти переменные никак не буду связаны между собой. Спецификация класса памяти extern используется для объявления переменной, определенной где-то в другом месте программы. Такие объявления используются в случае, когда нужно распространить на данный исходный файл область видимости переменной, определенной в другом исходном файле на внешнем уровне. Область видимости переменной распространяется от места объявления до конца исходного файла. В объявлениях, которые используют спецификацию класса памяти extern, инициализация не допускается, так как они ссылаются на переменные, значения которых определены в другом месте. Локальные переменные Переменная, объявленная на внутреннем уровне, доступна только в том, блоке в котором она объявлена, независимо от класса памяти. По умолчанию она имеет класс памяти auto. Переменные этого класса размещаются в стеке. Переменные класса памяти auto автоматически не инициализируются, поэтому в случае отсутствия инициализации в объявлении значение переменной класса памяти auto считается неопределенным. Спецификация класса памяти register требует, чтобы переменной была выделена память в регистре, если это возможно. Т.к. работа с регистрами происходит быстрее, спецификация класса памяти register обычно используется для переменных, к которым предполагается обращаться очень часто. Для каждого рекурсивного входа в блок порождается новый набор переменных класса памяти auto и register. При этом каждый раз производится инициализация переменных, в объявлении которых заданы инициализаторы. Если переменная, объявленная на внутреннем уровне, имеет спецификацию памяти static, то область видимости остается прежней, а время жизни становится глобальным. В отличие от переменных класса памяти auto, переменные, объявленные со спецификацией класса памяти static, сохраняют свое значение при выходе из блока. Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то переменная класса памяти static автоматически инициализируется нулевым значением. Инициализация выполняется один раз во время компиляции и не повторяется при каждом входе в бока. Все рекурсивные вызовы данного бока будут разделять единственный экземпляр переменной класса памяти static. Переменная, объявленная со спецификацией класса памяти extern, является ссылкой на переменную с тем же самым именем, определенную на внешнем уровне в любом исходном файле программы. Цель внутреннего объявления extern состоит в том, чтобы сделать определение переменной доступным именно внутри данного блока. Объявление имени в блоке может скрыть объявление этого имени в охватывающем блоке или глобальное имя. То есть имя может быть замещено внутри блока и будет ссылаться там на другую сущность. После выхода из блока имя восстанавливает свой прежний смысл. К скрытому глобальному имени можно обратиться с помощью операции разрешения области видимости ::. Скрытое имя члена класса можно использовать, квалифицировав его именем класса. Скрытое глобальное имя можно использовать, если квалифицировать его унарной операцией разрешения области видимости. · Конструктор, деструктор и аллокатор в С++. Конструктор — это особая функция-член, инициализирующая экземпляр своего класса.Конструкторы имеют имена, совпадающие с именами классов, и не имеют возвращаемых значений.У конструктора может быть любое число параметров, а у класса — любое число перегруженных конструкторов.Конструкторы могут иметь любой уровень доступа — открытый, защищенный или закрытый.Если вы не определили ни одного конструктора, компилятор создаст конструктор по умолчанию, не имеющий параметров. Это поведение можно переопределить, объявив конструктор по умолчанию как удаленный. Функции-деструкторы представляют собой противоположность конструкторам.Они вызываются при уничтожении (отмене выделения памяти) объектов.Для того чтобы указать функцию как деструктор класса, необходимо указать перед именем класса знак тильды (~).Например, деструктор для класса String объявляется следующим образом: ~String(). При компиляции с параметром /clr деструктор имеет специальную роль, которая заключается в высвобождении управляемых и неуправляемых ресурсов. // spec1_destructors.cpp#include <string.h> class String {public: String( char *ch ); // Declare constructor ~String(); // and destructor.private: char *_text; size_t sizeOfText;}; // Define the constructor.String::String( char *ch ) { sizeOfText = strlen( ch ) + 1; // Dynamically allocate the correct amount of memory. _text = new char[ sizeOfText ]; // If the allocation succeeds, copy the initialization string. if( _text ) strcpy_s( _text, sizeOfText, ch );} // Define the destructor.String::~String() { // Deallocate the memory that was previously reserved // for this string. if (_text) delete[] _text;} int main() { String str("The piper in the glen...");} Деструкторы — это функции с тем же именем, что и класс, но с добавленным в начало знаком тильды (~). Первая форма синтаксиса используется для деструкторов, объявленных или определенных внутри объявления класса; вторая форма используется для деструкторов, определенных вне объявления класса. При объявлении деструкторов действуют несколько правил.Деструкторы: - Не могут иметь аргументов.
- Не могут иметь возвращаемого типа (включая void).
- Не могут возвращать значение с помощью оператора return.
- Не могут объявляться как const, volatile или static.Однако их можно вызывать для уничтожения объектов, объявленных как const, volatile или static.
- Могут объявляться как virtual.Используя виртуальные деструкторы, можно уничтожать объекты, не зная их тип — правильный деструктор для объекта вызывается с помощью механизма виртуальных функций.Обратите внимание, что для абстрактных классов деструкторы также могут объявляться как чисто виртуальные функции.
Деструкторы вызываются, когда происходит одно из следующих событий: - Объект, предоставленный с использованием оператора new, можно явно освободить с использованием оператора delete.Если объекты освобождаются с помощью оператора delete, память освобождается для "наиболее производного объекта" или объекта, который является полным, а не вложенным объектом, представляющим базовый класс.Освобождение "самого производного объекта" гарантированно работает только с виртуальными деструкторами.Освобождение может завершиться ошибкой в случае множественного наследования, если сведения о типе не соответствуют базовому типу фактического объекта.
- Локальный (автоматический) объект с областью видимости "блок" выходит за пределы области видимости.
- Время существования временного объекта заканчивается.
- Программа заканчивается, глобальные или статические объекты продолжают существовать.
- Деструктор явно вызываться с использованием полного имени функции деструктора.
Когда объект выходит за пределы области или удаляется, последовательность событий при его полном уничтожении выглядит следующим образом: - Вызывается деструктор класса, и выполняется тело функции деструктора.
- Деструкторы для объектов нестатических членов вызываются в порядке, обратном порядку их появления в объявлении класса.Необязательный список инициализации членов, используемый при создании этих членов, не влияет на порядок (создания или) уничтожения.(Дополнительные сведения об инициализации членов см. в разделе Инициализация базовых классов и членов.)
- Деструкторы для невиртуальных базовых классов вызываются в порядке, обратном порядку их объявления.
- Деструкторы для виртуальных базовых классов вызываются в порядке, обратном порядку их объявления.
Класс шаблона описывает объект, который управляет выделением и освобождением памяти для массивов объектов типа Тип. Объект класса allocator является объектом распределителя по умолчанию, заданным в конструкторах для нескольких классов шаблонов контейнеров в стандартной библиотеке C++. template <class Type >class allocator Параметры Тип Тип объекта, для которого выполняется выделение и освобождение памяти. Таким образом, распределитель определяет следующие типы: - pointer действует как указатель на Type.
- const_pointer действует как константный указатель на Type.
- reference действует как ссылка на Type.
- const_reference действует как константная ссылка на Type.
Эти типы Type определяют форму, какую должны принимать указатели и ссылки для выделенных элементов. (allocator::pointer не обязательно совпадает с Type* для всех объектов распределителя, даже если он содержит это очевидное определение для класса allocator.) · Перегрузка операторов в С++. Перегрузка операторов — в программировании — один из способов реализации полиморфизма, заключающийся в возможности одновременного существования в одной области видимости нескольких различных вариантов применения оператора, имеющих одно и то же имя, но различающихся типами параметров, к которым они применяются. Перегрузка операций предполагает введение в язык двух взаимосвязанных особенностей: возможности объявлять в одной области видимости несколько процедур или функций с одинаковыми именами и возможности описывать собственные реализации бинарных операторов (то есть знаков операций, обычно записываемых в инфиксной нотации, между операндами). Принципиально реализация их достаточно проста: - Чтобы разрешить существование нескольких одноимённых операций, достаточно ввести в язык правило, согласно которому операция (процедура, функция или оператор) опознаются компилятором не только по имени (обозначению), но и по типам их параметров. Таким образом, abs(i), где i объявлено как целое, и abs(x), где x объявлено как вещественное — это две разные операции. Принципиально в обеспечении именно такой трактовки нет никаких сложностей.
- Чтобы дать возможность определять и переопределять операции, необходимо ввести в язык соответствующие синтаксические конструкции. Вариантов их может быть достаточно много, но по сути они ничем друг от друга не отличаются, достаточно помнить, что запись вида «<операнд1> <знакОперации> <операнд2>» принципиально аналогична вызову функции «<знакОперации>(<операнд1>,<операнд2>)». Достаточно разрешить программисту описывать поведение операторов в виде функций — и проблема описания решена.
· Библиотека Standard Template Library (STL). Библиотека стандартных шаблонов (STL) (англ. Standard Template Library) — набор согласованных обобщённых алгоритмов, контейнеров, средств доступа к их содержимому и различных вспомогательных функций в C++. В библиотеке выделяют пять основных компонентов: - Контейнер (англ. container) — хранение набора объектов в памяти.
- Итератор (англ. iterator) — обеспечение средств доступа к содержимому контейнера.
- Алгоритм (англ. algorithm) — определение вычислительной процедуры.
- Адаптер (англ. adaptor) — адаптация компонентов для обеспечения различного интерфейса.
- Функциональный объект (англ. functor) — сокрытие функции в объекте для использования другими компонентами.
STL обладает рядом преимуществ: · Код библиотеки написан профессиональными программистами, проверен и отлажен. Вам не придётся искать ошибки в реализации контейнеров или алгоритмов STL. Скорее, ошибки будут связаны с неверным пониманием концепций STL, но это вопрос опыта использования. · Код библиотеки написан очень эффективно с точки зрения использования оперативной памяти и быстродействия для типовых вариантов применения. · Библиотека предлагает унифицированный интерфейс, однообразный для всех контейнеров и алгоритмов, что после получения навыка использования библиотеки позволяет значительно повысить читаемость программы. · Использование библиотеки позволяет приступить сразу к решению проектных задач, не задумываясь о реализации низкоуровневых контейнеров и алгоритмов. В случае работы проектной группы это позволяет избежать дублирования кода у различных разработчиков. · Библиотека хорошо документирована и описана в книгах. В случае разработки собственных контейнеров и алгоритмов документация будет, скорее всего, значительно беднее, что повысит стоимость подготовки нового специалиста. · Код, написанный с использованием STL легко переносится на другие компиляторы, операционные системы и платформы. К недостаткам STL можно отнести: · Неприспособленность к работе со структурными типами данных. · Низкая эффективность (быстродействие, память) при решении частных задач, где возможны целевые оптимизации кода. · Неадекватный интерфейс шаблона для работы со строками · Сложность управления пулом памяти при работе с контейнерами STL. Контейнеры Библиотека STL представляет ряд контейнеров для хранения данных, которые условно можно разделить на контейнеры с произвольным доступом, последовательные контейнеры и ассоциативные контейнеры Контейнерами с произвольным доступом являются vector и deque. Оба контейнера обеспечивают произвольный доступ к элементам (как к элементам обычных массивов C++). Основное отличие vector и deque состоит в том, что vector обеспечивает добавление новых элементов в конце, а deque – в конце и в начале контейнера. Строки Шаблон sting реализует функционал, необходимый для работы со строками текста. В отличии от стандартного представления строки в виде массива символов константной длинны шаблон string динамически распределяет память для строки в пуле и гарантирует достаточный объём памяти при любых операциях со строками: вводе, слиянии строк и т.д. Шаблон обеспечивает освобождение памяти, занятого строковым объектом, после того, как он станет не нужен. Методы шаблона обеспечивают все необходимые алгоритмы работы со строками: поиск, замену, вставку, сравнение. Использование шаблона string значительно упрощает работу со строками для начинающего программиста. Итераторы Итераторы используются для доступа к элементам контейнеров также, как указатели используются для доступа к элементам массивов в С++. Итератор является «умным» указателем на элемент контейнера. В отличие от обычного указателя он помнит полный тип данных на который ссылается – с учётом типа контейнера, к элементу которого производится обращение. Итераторы бывают нескольких типов – входные, выходные, прямые, двунаправленные и произвольного доступа. Тип итератора определяет подмножество операторов, применимых к нему. Например, итератор произвольного доступа поддерживает возможность добавления определённого смещения (i+n), в то время, как другие итераторы позволяют только операции смещения итератора на одну позицию i++ или ++i. Двунаправленные итераторы позволяют перемещаться и в обратном направлении (i-- и --i). Алгоритмы Библиотека STL предоставляет основные виды алгоритмов: - Математические (расчёт сумм, произведений, генерация случайных значений)
- Поиска (минимальное значение, поиск последовательности, подсчёт числа значений)
- Сортировки
- Работы с последовательностями (объединение последовательностей, сравнения, обработки последовательности типовой операцией)
Предикаты, функторы и адаптеры Функтором (или функциональным объектом) называется любой объект, к которому можно применить оператор вызова функции - operator(). Такой вызов в С++ применим к имени функции, указателю на функцию или объекту класса, который переопределяет operator(). Предикатом называется функция (или функциональный объект), которая в зависимости от значения аргументов может возвращать либо true, либо false. |