ТОП 10:

Консруктор во множественном наследовании



ВС++ существует возможность использования более одного класса в качестве базового. Такой механизм наследования называется множественным наследованием. При множественном наследовании объекты производных классов могут использовать данные и методы нескольких классов, а также в свою очередь быть базовыми классами для других. Рассмотрим как задаются производные классы от более чем одного базового класса: classderived: атрибут_наследованияbase1, ...,

атрибут_наследованияbaseN{...};

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

Конструктор_производного_класса (аргументы) :

base1(аргументы), ... ,baseN(аргументы){...}

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

Виртуальные функции. Переопределение виртуальной функции.

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

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

virtual возвращаемый_тип имя (аргументы) =0;

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

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

Класс, содержащий хотя бы один чисто виртуальный метод (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');
Разделитель извлекается из потока, но в буфер не заносится. Это основная функция для извлечения строк из потока. Считанные символы завершаются нулевым символом.







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

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