Основы ООП. Понятие инкапсуляции, наследования и полиморфизма. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Основы ООП. Понятие инкапсуляции, наследования и полиморфизма.



Основы ООП. Понятие инкапсуляции, наследования и полиморфизма.

Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция — это набор всех таких характеристик.

Инкапсуляция — это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя.

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

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

Сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса или копирования прототипа (например, после запуска результатов компиляции и связывания исходного кода на выполнение).

Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

Прототип — это объект-образец, по образу и подобию которого создаются другие объекты. Объекты-копии могут сохранять связь с родительским объектом, автоматически наследуя изменения в прототипе; эта особенность определяется в рамках конкретного языка.

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

Инкапсуляция (encapsulation) — это механизм, который объединяет данные и код, манипулирующий с этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создается так называемый "черный ящик". Когда коды и данные объединяются таким способом, создается объект (object). Другими словами, объект — это то, что поддерживает инкапсуляцию.

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

Ограничение на наследование

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

Полиморфизм – дословный перевод с греческого «много форм». В С++ полиморфизм реализуется с помощью виртуальных функций, которые позволяют в рамках всей иерархии классов иметь несколько версий одной и той же функции. Решение о том, какая именно версия должна выполняться в данный момент, определяется на этапе выполнения программы и носит название позднего связывания.

Класс в ООП и его основные компоненты.

Класс (class) – это тип, определяемый пользователем, включающий в себя данные и функции, называемые методами или функциями-членами класса.

Данные класса – это то, что класс «знает».

Функции – члены (методы) класса – это то, что класс «делает».

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

Объявление класса

class my_Fun

{// компоненты-данные

double x,y;

// компоненты-функции

public:

// функция инициализации

void set(char *c,double X)

{x=X;y=sin(x); }

// функция вывода результатов

void print(void)

{cout << point<<y << endl; }};

Обычно описания классов включают в заголовочные файлы (*.H), а реализацию функций-членов классов – в файлы *.CPP.

Для каждого объекта класса устанавливается область видимости либо явно – указанием уровня доступа одним из ключевых слов public, private, protected с двоеточием, либо неявно – по умолчанию. Указание области видимости относится ко всем последующим объектам класса, пока не встретится указание другой области видимости. Область видимости public разрешает доступ к объектам класса из любой части программы, в которой известен этот объект (общедоступный). Область видимости private разрешает доступ к объектам класса только из методов этого класса. Объекты с такой областью видимости называют частными. Область видимости protected определяется для защищенных объектов, она имеет смысл только в иерархической системе классов и разрешает доступ к объектам этой области из методов производных классов. В теле класса ключевое слово области видимости может использоваться неоднократно. Область видимости для объектов типа «класс» по умолчанию private.

 

Перегрузка функций.

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

Компилятор определяет, какую именно функцию требуется вызвать, по типу фактических параметров. Этот процесс называется разрешением перегрузки (перевод «уточнение»). Тип возвращаемого функцией значения в разрешении не участвует. Механизм разрешения основан на достаточно сложном наборе правил, смысл которых сводится к тому, чтобы использовать функцию с наиболее подходящими аргументами и выдать и выдать сообщение, если такой не найдется. Допустим, имеется четыре варианта функции, определяющей наибольшее значение:

//Возвращает наибольшее из двух целых:

int max(int. int);

//Возвращает подстроку наибольшей длины:

char*max(char*.char);

При вызове функции max компилятор выбирает соответствующий типу фактических параметров вариант функции (в приведённом примере будут последовательно вызваны все четыре варианта функции).

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

Неоднозначность может появиться при:

преобразовании типа;

использовании параметров-ссылок;

использоваии аргументов по умолчанию.

Пример неоднозначности: если одна из перегружаемых функций объявлена как int f(int a,int b), а другая – как int f(int a, int&b), то компилятор не сможет узнать, какая из этих функций вызывается, так как нет синтаксических различий между вызовом функции, которая получет параметр по значению, и вызовом функции, которая получает параметр по ссылке.

Правило описания перегруженных функций

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

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

Функции не могут быть перегружены, если описание их параметров отличается только модификатором const или использованием ссылки (например, int и const int или int и int&).

 

Объявление класса

class my_Fun

{// компоненты-данные

double x,y;

// компоненты-функции

public:

// функция инициализации

void set(char *c,double X)

{x=X;

y=sin(x); }

void print(void) // функция вывода результатов {cout << point<<y << endl; }};

Обычно описания классов включают в заголовочные файлы (*.H), а реализацию функций-членов классов – в файлы *.CPP.

Для каждого объекта класса устанавливается область видимости либо явно – указанием уровня доступа одним из ключевых слов public, private, protected с двоеточием, либо неявно – по умолчанию. Указание области видимости относится ко всем последующим объектам класса, пока не встретится указание другой области видимости. Область видимости public разрешает доступ к объектам класса из любой части программы, в которой известен этот объект (общедоступный). Область видимости private разрешает доступ к объектам класса только из методов этого класса. Объекты с такой областью видимости называют частными. Область видимости protected определяется для защищенных объектов, она имеет смысл только в иерархической системе классов и разрешает доступ к объектам этой области из методов производных классов. В теле класса ключевое слово области видимости может использоваться неоднократно. Область видимости для объектов типа «класс» по умолчанию private.

Способы объявления и инициализации объектов и доступ к методам класса:

Прямой вызов

my_Fun Fun1;//объявление объекта1,но не инициализация

Fun1.set("Function1 = ",1.0);// инициализация данных

Fun1.print(); // прямой вызов

cout << "Input enter1..." << endl<<endl;

Косвенный вызов

my_Fun *p1 = &Fun1; // воспользовались объектом 1

// новая инициализация

p1->set("Function1 = ",1.0); // косвенный вызов

p1->print(); // косвенный вызов

cout << "Input enter1..." << endl<<endl;

Динамическое выделение памяти

my_Fun *p1 = new my_Fun;

p1->set("Function1 = ",1.0); // косвенный вызов

p1->print(); // косвенный вызов

cout << "Input enter1..." << endl<<endl;// удаляется динамически выделенный объект

delete p1;

 

Указатель «this». Пример явного использования.

Когда функция-элемент ссылается на другой элемент какого-то объекта данного класса, откуда у С++ берется уверенность, что имеется ввиду соот­ветствующий объект? Ответ заключается в том, что каждый объект сопровождается указателем на самого себя — называемым указателем this — это неявный аргумент во всех ссылках на элементы внутри этого объекта. Указатель this можно использовать также и явно. Каждый объект может определить свой собственный адрес с помощью ключевого слова this.

Указатель this неявно используется для ссылки как на данные-элементы, так и на функции-элементы объекта. Тип указателя this зависит от типа объекта и от того, объявлена ли функция-элемент, в которой используется this, как const. В неконстантной функции-элементе класса Employee указатель this имеет тип Employee * const (константный указатель на объект Employee). В константной функции-элементе класса Employee указатель this имеет тип const Employee * const (константный указатель на объект Employee, который тоже константный).

Несмотря на то, что указатель на объект не передаётся явно, к нему можно получить доступ внутри метода. Его имя - this (this - этот; читается как нечто среднее между вис и зис). Давайте посмотрим на пример использования этого указателя:

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

Пример:

class test

{

public:

int* a;

test() // конструктор

{ a = new int;}

test (test& t) // копирующий конструктор

{ a = new int;

memcpy (a, t.a, 4); }

test& operator= (test& t) // операция присваивания

{ a = new int;

memcpy (a, t.a, 4);

return (*this); }

~test() // деструктор

{ delete a;}};

 

Функции-друзья класса.

Дружественная функция - это функция, которая, не являясь компонентой класса, имеет доступ к его защищенным и собственным компонентам. Служит для расширения интерфейса класса. Описана в теле класса со спецификатором friend. friend имя_функции (список_формальных_параметров);

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

 

 

Функции-деструкторы.

Функцией, обратной конструктору, является деструктор (destructor). Эта функция вызывается при удалении объекта. Обычно при работе с объектом в момент его удаления должны выполняться некоторые действия. Например, при создании объекта для него выделяется память, которую необходимо освободить при его удалении. Имя деструктора совпадает с именем класса, но с символом ~ (тильда) в начале.

Деструктор вызавается автоматически, когда объект выходит из области видимости:

для локальных объектов – при выходе из блока, в котором они объявлены;

для глобальных – как часть процедуры выхода из main;

для объектов, заданных через указатели, деструктор вызывается неявно при использовании операции delete

Десруктор не имеет аргументов и возвращаемого значения, не может быть объявлен как const или static;не наследуется, может быть виртуальным

monstr::~monstr(){delete [] name;}

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

Виртуальный базовый класс

В языке С++ запрещено непосредственно передавать базовый класс в производный более одного раза, т.е. имя класса в списке базовых классов не может повторяться. Однако могут возникать ситуации, когда один производный класс косвенно может наследовать один и тот же базовый класс через другие базовые классы.Такое наследование вполне возможно и компилятор не выдаст сообщение об ошибке, а только предупредит, что наследуемый класс A также находится и в наследуемом классе B. Если один базовый класс косвенно наследуется в одном производном классе и наследуется с атрибутом virtual, то в экземпляр производного класса будет помещена только одна копия базового класса. Базовый класс объявляется как виртуальный только при наследовании - в списке базовых классов с указанием спецификатора virtual:

class A {...};

class B:virtual public A{...};

class C:virtual public A, public B {...};

Следует отметить, что если базовый класс наследуется производным как виртуальный, то его компоненты все равно доступны в производном классе. Отличие между обычным и виртуальным наследованием заключается в том, что когда класс наследует базовый класс более одного раза, то он будет содержать только одно вхождение базового класса.При виртуальном наследовании базовых классов в первую очередь вызываются конструкторы виртуальных базовых классов в порядке наследования. Так, в нашем примере первым будет вызван конструктор виртуального класса А, затем конструктор виртуального класса С, затем конструктор базового класса B, и последним будет вызван конструктор производного класса. Деструкторы вызываются в обратном порядке. В случае, если базовый класс C наследовался бы как не виртуальный, то порядок вызова конструкторов был бы следующий: конструктор класса А, конструктор класса В, конструктор класса С, конструктор класса D. И последнее, если базовый класс А наследовался бы как не виртуальный, то это привело бы к ошибке на стадии компиляции.

 

Понятие абстрактного класса

Класс, содержащий хотя бы один чисто виртуальный метод (virtual возвращаемый_тип имя (аргументы) =0), называется абстрактным. Абстр.классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах. Абстр. класс может использоваться только в качестве базового для других классов – объекты абстрактного класса создавать нельзя, поскольку прямой или косвенный вызов чисто виртуального метода приводит к ошибке при выполнении. Абстр. класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функцией значения. Допускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать временный объект. Если класс, производный от абстрактного, не определяет все чисто виртуальные функции, он также является абстрактным. Т.о., можно создать функцию, параметром которой является указатель на абстрактный класс. На место этого параметра при выполнении программы может передаваться указатель на объект любого производного класса. Это позволяет создавать полиморфные функции, работающие с объектом любого ипа в пределах одной иерархии.

 

Перегрузка методами класса

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

При вызове перегруженного метода использует тип и/или количество аргументов метода. Следовательно, перегруженные методы должны различаться по типу и/или количеству их параметров. Хотя возвращаемые типы перегруженных методов могут быть различны, самого возвращаемого типа не достаточно для различения двух версий метода. Когда си++ встречает вызов перегруженного метода, она просто выполняет ту его версию, параметры которой соответствуют аргументам, использованным в вызове.

 

Итераторы

Для доступа к элементам некоторого множества элементов алгоритмы stl используют специальные объекты, называемые итераторами. В контейнерных типах stl они доступны через методы класса (например, begin() в шаблоне класса vector). Функциональные возможности указателей и итераторов близки, так что обычный указатель тоже может использоваться как итератор.

категории итераторов

итератор ввода (input iterator) - используется потоками ввода;

итератор вывода (output iterator) - используется потоками вывода;

однонаправленный итератор (forward iterator) - для прохода по элементам в одном направлении;

двунаправленный итератор (bidirectional iterator) - способен пройтись по элементам в любом направлении. Такие итераторы реализованы в некоторых контейнерных типах stl (list, set, multiset, map, multimap);

итераторы произвольного доступа (random access) - через них можно иметь доступ к любому элемента. Такие итераторы реализованы в некоторых контейнерных типах stl (vector, deque, string, array). Также определена специализация шаблона iterator_traits, позволяющая использовать обычные указатели в качестве итераторов.

пользовательский итератор

Пользовательские итераторы создаются как наследники от шаблона класса iterator. Для использования итератора в алгоритмах stl определяются указанные выше операции (по необходимости перегружаются и те три функции).

 

Алгоритмы

Алгоритмы предназначены для работы с контейнерами и другими последовательностями. Каждый алгоритм реализован в виде шаблона или набора шаблонов функции, поэтому может работать с различными видами последовательностей и данными разнообразных типов. Для настройки алгоритма на конкретные требования пользователя применяються функциональные объекты. Использование стандартных алгоритмов, как и других средств стандартной библиотеки, избавляет программиста от написания, отладки и документирования циклов обработки последователностей, что уменьшает количество ошибок в программе снижает время её разработки и делает её более читаемой и компактной. Объявление стандартных алгоритмов находятся в заголовочном файле <algorithm>,стандартных функциональных объектов-в файле <functional>. Все алгоритмы можно разделить на 4 категории: немодифицирующие операции с последовательностями;модефицирующие операции с последовательностями; алгоритмы, связанные с сортировкой; алгоритмы работы с можествами и пирамидоми; Кроме того, библиотека содержит обобщённые численные алгоритмы, объявление которых находиться в файле <numeric>. Вкачестве параметров алгоритму передаються итераторы, определяющие начало и конец обрабатываетмой последовательности. Вид итераторов определяет типы контейнеров, для которых можит использоваться данный алгоритм. In – итератор для чтения, Out- итератор для записи, For- прямой итератор, Bi- двунаправленный итератор, Ran- итератор произвольного доступа, Comp-функция сравнения, Op-унарная операция, BinOp-бинарная операция.

 

Потоковые классы.

Библиотека потоковых классов С++ построена на основе двух базовых классов: ios и streambuf.

Класс streambuf обеспечивает организацию и взаимосвязь буферов ввода-вывода, размещаемых в памяти, с физическими устройствами ввода-вывода. Методы и данные класса streambuf программист явно обычно не использует. Этот класс нужен другим классам библиотеки ввода-вывода. Он доступен и программисту для создания новых классов на основе уже существующих.

Класс ios содержит средства для форматированного ввода-вывода и проверки ошибок.

Стандартные потоки (istream, ostream, iostream) служат для работы с терминалом. Строковые потоки (istrstream, ostrstream, strstream) служат для ввода-вывода из строковых буферов, размещенных в памяти. Файловые потоки (ifstream, ofstream, fstream) служат для работы с файлами:

ios -базовый потоковый класс; streambuf -буферизация потоков;istream -потоки ввода; ostream -потоки вывода;

Для ввода с потока используются объекты класса istream, для вывода в поток - объекты класса ostream.

В классе istream определены следующие функции:

-istream& get(char *buffer, int size, char delimiter = '\n');
Эта функция извлекает символы из istream и копирует их в буфер. Операция прекращается при достижении конца файла, либо когда скопированы size символов, либо при обнаружении указанного разделителя. Сам разделитель не копируется и остается в streambuf. Последовательность прочитанных символов всегда завершается нулевым символом.

-istream& read(char *buffer, int size);
Не поддерживает разделителей, и считанные в буфер символы не завершаются нулевым символом.

-istream& getline(char *buffer, int size, char delimiter = '\n');
Разделитель извлекается из потока, но в буфер не заносится. Это основная функция для извлечения строк из потока. Считанные символы завершаются нулевым символом.

Файловые потоки.

Потоки для работы с файлами создаются как объекты следующих классов:

ofstream - запись в файл; ifstream - чтение из файла; fstream - чтение/запись.

Для создания потоков имеются следующие конструкторы:

fstream();создает поток, не присоединяя его ни к какому файлу.

fstream(constchar *name, int mode, int p = filebuf::openprot);создает поток, присоединяет его к файлу с именем name, предварительно открыв файл, устанавливает для него режим mode и уровень защиты p. Если файл не существует, то он создается. Для mode = ios::out, если файл существует, то его размер будет усечен до нуля. Флаги режима определены в классе ios и имеют следующие значения:

in - для чтения out - для записи

Если при создании потока он не присоединен к файлу, то присоединить существующий поток к файлу можно функцией void open(const char *name, int mode, int p = filebuf::openprot);

Функция void fstream base::close(); сбрасывает буфер потока, отсоединяет поток от файла и закрывает файл. Эту функцию необходимо явно вызвать при изменении режима работы с потоком. Автоматически она вызывается только при завершении программы.

Таким образом, создать поток и связать его с файлом можно тремя способами:

1. Создается объект filebuf filebuf fbuf;

Объект filebuf связывается с устройством (файлом) fbuf.open("имя", ios::in);

Создается поток и связывается с filebuf istream stream(&fbuf);

2. Создается объект fstream (ifstream, ofstream) fstream stream;

Открывается файл, который связывается через filebuf с потоком stream.open("имя", ios::in);

3. Создается объект fstream, одновременно открывается файл, который связывается с потоком fstream stream("имя", ios::in).

ОПРЕДЕЛЕНИЕ КОНЦА ФАЙЛА

Обычной файловой операцией в программах является чтение содержимого файла, пока не встретится конец файла. Чтобы определить конец файла, ваши программы могут использовать функцию еоf потокового объекта. Эта функция возвращает значение 0, если конец файла еще не встретился, и 1, если встретился конец файла. Используя цикл while, программы могут непрерывно читать содержимое файла, пока не найдут конец файла, как показано ниже:

while (! input_file.eof()){// Операторы}

ПРОВЕРКА ОШИБОК ПРИ ВЫПОЛНЕНИИ ФАЙЛОВЫХ ОПЕРАЦИЙ

Если ваша программа пишет данные в файл, вам необходимо убедиться, что операция прошла успешно (к примеру, отсутствие места на диске, скорее всего, помешает записи данных). Чтобы помочь программам следить за ошибками, вы можете использовать функцию fail файлового объекта. Если в процессе файловой операции ошибок не было, функция возвратит ложь (0). Однако, если встретилась ошибка, функция fail возвратит истину. Например, если программа открывает файл, ей следует использовать функцию fail, чтобы определить, произошла ли ошибка, как это показано ниже:

ЗАКРЫТИЕ ФАЙЛА, ЕСЛИ ОН БОЛЬШЕ НЕ НУЖЕН

При завершении программы операционная система закроет открытые ею файлы. Однако, как правило, если программе файл больше не нужен, она должна его закрыть. Для закрытия файла программа должна использовать функцию close:

input_file.close ().

 

Шаблоны функций

Шабло́ны (англ. template) — средство языка C++, предназначенное для кодирования обобщённых алгоритмов, без привязки к некоторым параметрам (например, типам данных, размерам буферов, значениям по умолчанию).

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

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

Шаблон функции начинается с ключевого слова template, за которым в угловых скобках следует список параметров. Затем следует объявление функции:

template< typename T >

void sort(T array[], int size); // прототип: шаблон sort объявлен, но не определён

template< typename T >

void sort(T array[], int size) // объявление и определение

{

T t;

for (int i = size - 1; i > 0; i--)

for (int j = i; j > 0; j--)

if (array[j] < array[j-1])

{

t = array[j];

array[j] = array[j-1];

array[j-1] = t;

}}

template< int BufferSize > // целочисленный параметр

char* read()

{ char *Buffer = new char[ BufferSize ];

/* считывание данных */

return Buffer;}

 

Шаблоны классов.

Шабло́ны (англ. template) — средство языка C++, предназначенное для кодирования обобщённых алгоритмов, без привязки к некоторым параметрам (например, типам данных, размерам буферов, значениям по умолчанию).

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

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

template< class T >

class List

{

public:

void Add(const T& Element);

bool Find(const T& Element);

};

[править]

Использование шаблонов

Для использования шаблона класса, необходимо указать его параметры. В качестве параметров могут использоваться типы, шаблоны и переменные. Типы могут быть как стандартными так и определёнными пользователем.

 

Указатель типа «void».

В C++ существует специальный тип указателя, который называется указателем на неопределённый тип. Для определения такого указателя вместо имени типа используется ключевое слово void в сочетании с описателем, перед которым располагается символ ptrОперации *.

void *UndefPoint;

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

Поэтому переменной UndefPoint невозможно присвоить никаких значений без явного преобразования этих значений к определённому типу указателя.

UndefPoint = 0xb8000000; // Такое присвоение недопустимо.

Объектам типа указатель на объект неопределённого типа в качестве значений разрешается присваивать значения лишь в сочетании с операцией явного преобразования типа.

В этом случае указатель на объект неопределённого типа становится обычным указателем на объект какого-либо конкретного типа. Со всеми вытекающими отсюда последствиями. Для указателя на объект неопределённого типа не существует способа непосредственной перенастройки указателя на следующий объект с помощью операции инкрементации.

 

Операция «typeid»

Для динамической идентификации типов применяются операторы dynamic_cast и typeid (определён в файле typeinfo.h), для использования которых информацию о типах во время выполнения обычно необходимо добавить через опции компилятора при компиляции модуля.

Оператор dynamic_cast пытается выполнить приведение к указанному типу с проверкой. Целевой тип операции должен быть типом указателя, ссылки или void*.

Если целевой тип — тип указателя, то аргументом должен быть указатель на объект класса.

Если целевой тип — ссылка, то аргумент должен также быть соответствующей ссылкой.

Если целевым типом является void*, то аргумент также должен быть указателем, а результатом операции будет указатель, с помощью которого можно обратиться к любому элементу «самого производного» класса иерархии, который сам не может быть базовым ни для какого другого класса.

Оператор typeid возвращает ссылку на структуру type_info, которая содержит поля, позволяющие получить информацию о типе.

Основы ООП. Понятие инкапсуляции, наследования и полиморфизма.

Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция — это набор всех таких характеристик.

Инкапсуляция — это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя.

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

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

Сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса или копирования прототипа (например, после запуска результатов компиляции и связывания исходного кода на выполнение).

Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

Прототип — это объект-образец, по образу и подобию которого создаются другие объекты. Объекты-копии могут сохранять связь с родительским объектом, автоматически наследуя изменения в прототипе; эта особенность определяется в рамках конкретного языка.

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

Инкапсуляция (encapsulation) — это механизм, который объединяет данные и код, манипулирующий с этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создается так называемый "черный ящик". Когда коды и данные объединяются таким способом, создается объект (object). Другими словами, объект — это то, что поддерживает инкапсуляцию.

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

Ограничение на наследование

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

Полиморфизм – дословный перевод с греческого «много форм». В С++ полиморфизм реализуется с помощью виртуальных функций, которые позволяют в рамках всей иерархии классов иметь несколько версий одной и той же функции. Решение о том, какая именно версия должна выполняться в данный момент, определяется на этапе выполнения программы и носит название позднего связывания.



Поделиться:


Последнее изменение этой страницы: 2016-08-26; просмотров: 2489; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.220.65.61 (0.182 с.)