Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Не будет виртуальным. Виртуальные деструкторы




Таблица виртуальных функций

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

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

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

Случаи, когда вызов виртуальной функции не будет виртуальным

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

Виртуальные деструкторы

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

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

 

 

Ввод-вывод файлов. Потоки ввода-вывода. Библиотека ввода-вывода (iostream). Группы классов библиотеки ввода вывода

Для начала рассмотрим пример:

#include <stream.h>

main()

{

cout << "Hello, world\n";

}

Строка #include <stream.h> сообщает компилятору, чтобы он включил стандартные возможности потока ввода и вывода, находящиеся в файле stream.h. Без этих описаний выражение cout << "Hello, world\n" не имело бы смысла. Операция << ("поместить в") пишет свой первый аргумент во второй (в данном случае, строку "Hello, world\n" в стандартный поток вывода cout). Программирующим на C << известно как операция сдвига влево для целых. Такое использование << не утеряно, просто в дальнейшем << было определено для случая, когда его левый операнд является потоком вывода.

Ввод производится с помощью операции >> ("извлечь из") над стандартным потоком ввода cin. Описания cin и >>, конечно же, находятся в <stream.h>. Операцию вывода << можно применять к ее собственному результату, так что несколько команд вывода можно записать одним оператором.

Потоки

Механизм для ввода-вывода в Си++ называется потоком. Название произошло от того,что информация вводится и выводится в виде потока байтов – символ за символом.

Класс istream реализует поток ввода, класс ostream – поток вывода. Эти классы определены в файле заголовков iostream.h. Библиотека потоков ввода-вывода определяет три глобальных объекта: cout,cin и cerr. cout называется стандартным выводом, cin – стандартным вводом, cerr – стандартным потоком сообщений об ошибках. cout и cerr выводят на терминал и принадлежат к классу ostream, cin имеет тип istream и вводит с терминала. Разница между cout и cerr существенна в Unix – они используют разные дескрипторы для вывода. В других системах они существуют больше для совместимости.

Вывод осуществляется с помощью операции <<, ввод с помощью операции >>. Выражение

cout << "Пример вывода: " << 34;

напечатает на терминале строку "Пример вывода", за которым будет выведено число 34. Выражение

int x;cin >> x;

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

Операции << и >> для потоков

В классах iostream операции >> и << определены для всех встроенных типов языка Си++ и для строк (тип char*). Если мы хотим использовать такую же запись для ввода и вывода других классов, определенных в программе, для них нужно определить эти операции.

Как показано в примере класса String, операция <<, во-первых, является не методом класса String, а отдельной функцией. Она и не может быть методом класса String, поскольку ее правый операнд – объект класса ostream. С точки зрения записи, она могла бы быть методом класса ostream, но тогда с добавлением нового класса приходилось бы модифицировать класс ostream, что невозможно – каждый бы модифицировал стандартные классы, поставляемые вместе с компилятором. Когда же операция << реализована как отдельная функция, достаточно в каждом новом классе определить ее, и можно использовать запись:

Во-вторых, операция << возвращает в качестве результата ссылку на поток вывода. Это позволяет использовать ее в выражениях типа приведенного выше, соединяющих несколько операций вывода в одно выражение.

Аналогично реализована операция ввода. Для класса istream она определена для всех встроенных типов языка Си++ и указателей на строку символов. Если необходимо, чтобы класс, определенный в программе, позволял ввод из потока, для него нужно определить операцию >> в качестве функции friend.

токовые классы представляют объектно-ориентированный вариант функций ANSI-C. Поток данных между источником и приемником при этом обладает следующими свойствами.

  • Источник или приемник данных определяется объектом потокового класса.
  • Потоки используются для ввода-вывода высокого уровня.
  • Потоковые классы делятся на три группы (шаблонов классов):
    • basic_istream, basic_ostream - общие потоковые классы, которые могут быть связаны с любым буферным объектом;
    • basic_ifstream, basic_iostream - потоковые классы для считывания и записи файлов;
    • basic_istringstream, basic_ostringstream - потоковые классы для объектов-строк.
  • Каждый потоковый класс поддерживает буферный объект, который предоставляет память для передаваемых данных, а также важнейшие функции ввода/вывода низкого уровня для их обработки.
  • Базовым шаблоном классов basic_ios (для потоковых классов) и basic_streambuf (для буферных классов) передаются по два параметра шаблона:
    • первый параметр (charT) определяет символьный тип;
    • второй параметр (traits) - объект типа ios_traits (шаблон класса), в котором заданы тип и функции, специфичные для используемого символьного типа;
    • для типов char и wchar_t образованы соответствующие объекты типа ios_traits и потоковые классы.

Пример шаблона потокового класса.

template<class charT, class traits = ios_traits<charT> >class basic_istream: virtual public basic_ios<charT, traits>;

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

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

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

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

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

ios базовый потоковый класс

streambuf буферизация потоков

istream потоки ввода

ostream потоки вывода

iostream двунаправленные потоки

iostream_withassign поток с переопределенной операцией присваивания

istrstream строковые потоки ввода

ostrstream строковые потоки вывода

strstream двунаправленные строковые потоки

ifstream файловые потоки ввода

ofstream файловые потоки вывода

fstream двунаправленные файловые потоки

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

iostream.h - для ios, ostream, istream.

strstream.h - для strstream, istrstream, ostrstream.

fstream.h - для fstream, ifstream, ofstream.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...