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

Полиморфизм и виртуальные функции. Применение динамического полиморфизма. Виртуальные деструкторы. Абстрактные классы и чисто виртуальные функции.

Читайте также:
  1. Lt;…> В чашу с чистою водой
  2. А какие примеры привести, объясняя, почему нельзя на себя надевать личины ведьм, вампиров, вурдалаков и просто нечистой силы?
  3. Абстрактные объекты теории и их системная организация
  4. Американская мечта в чистом виде
  5. Анализ формирования чистой прибыли
  6. Астрологическое применение слога ОМ
  7. Б. Регенерация нервных волокон как фактор, способствующий восстановлению нарушенной функции.

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

C++ упрощает создание полиморфных объектов.

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

Виртуальная (virtual) функция — это функция базового класса, перед именем которой стоит ключевое слово virtual.

Любой производный от базового класс может использовать или перегружать виртуальные функции.

Для создания полиморфного объекта вам следует использовать указатель на объект базового класса.

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

class Figure {

...

void Draw() const;

...

};

class Square: public Figure {

...

void Draw() const;

...

};

class Circle: public Figure {

...

void Draw() const;

...

};

В этом примере, какая из функций будет вызвана — Circle::Draw(), Square::Draw() или Figure::Draw(), определяется во время компиляции. К примеру, если написать

Figure* x = new Circle(0,0,5);

x->Draw();

то будет вызвана Figure::Draw(), поскольку x — объект класса Figure.

 

Но в C++ есть и динамический полиморфизм, когда вызываемая функция определяется во время выполнения. Для этого функции-члены должны быть виртуальными.

class Figure {

...

virtual void Draw() const;

...

};

class Square: public Figure {

...

virtual void Draw() const;

...

};

class Circle: public Figure {

...

virtual void Draw() const;

...

};

Figure* figures[10];

figures[0] = new Square(1, 2, 10);

figures[1] = new Circle(3, 5, 8);

...

for (int i = 0; i < 10; i++)

figures[i]->Draw();

 

В этом случае для каждого элемента будет вызвана Square::Draw() или Circle::Draw() в зависимости от вида фигуры.

 

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

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

class ANY_CLASS

{

public:

ANY_CLASS(); //конструктор по умолчанию

vrtual ~ANY_CLASS(); //а это - виртуальнный деструктор

};

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

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

Виртуальная функция -элемент некоторого класса может быть объявлена чистой. Это выглядит так:

virtual тип имя функции(список параметров} = 0;

Другими словами, тело функции объявляется как ='0 (т. н. чистый спецификатор). Действительная реализация ее не нужна (хотя и возможна). Предполагается, что чисто виртуальная функция будет переопределяться в классах, производных от него. Класс, объявляющий одну или несколько чисто виртуальных функций, является абстрактным базовым классом. Нельзя создать представитель такого класса. Он может служить только в качестве базового для порождения классов, которые полностью реализуют его чисто виртуальные функции.

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

Абстрактные классы

не могут, как уже сказано, иметь представителей;

не могут использоваться в качестве типа параметров или возвращаемых значений;

не могут участвовать в явных приведениях типа.

Тем не менее, можно объявлять указатели или ссылки на абстрактный класс.

Смысл абстрактных базовых классов в том, что они способствуют лучшей концептуальной организации классовой иерархии и позволяют тем самым в полной мере использовать преимущества виртуальных механизмов C++.


 

17. Ввод/вывод в C ++. Предопределенные потоки. Простота ввода/вывода в С ++. Потоки cin, cout и сегг. Операции выделения (>>) и вставки (<<).

В пакет компилятора Micrisoft Visual C++ включена стандартная библиотека, содержащая функции, часто используемые в среде C++. В C++ по-прежнему можно пользоваться библиотекой стандартного ввода/вывода С, описанной в заголовочном файле stdio.h. В C++ имеется другой заголовочный файл iostream.h, который реализует набор собственных функций ввода/вывода.

В языке C++ потоковый ввод/вывод описывается как набор классов в iostream.h. Эти классы используют перегруженные операции "занести в" и "получить из" << и >>.

В С отсутствуют встроенные операции ввода или вывода; функции, подобные printf(), являются частью стандартной библиотеки, но не самого языка. В C++ также нет встроенных средств ввода/вывода; это обеспечивает большую гибкость при разработке эффективного пользовательского интерфейса со структурами данных проектируемого приложения.

В языке C++ концепция класса обеспечивает модульное решение задачи манипуляции с данными. В стандартной библиотеке C++ имеются три класса ввода/вывода, являющиеся альтернативой функциям универсального ввода/вывода в С. Эти классы содержат описания для одной и той же пары операций, << и >>, которые оптимизируются для всех типов данных.

Аналогами потоков stdin, stdout и stderr, имеющих прототипы в файле stdio.h, в C++ являются cin, cout и сеrr, описанные в iostream.h. Эти три потока открываются автоматически при запуске программы и становятся интерфейсом между программой и пользователем. Поток cin связан с клавиатурой терминала. Потоки cout и сегг связаны с видеодисплеем.

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

эквивалентный оператор на C++: cout << "Integer value: " << lvalue << ", Float value: " << fvalue;

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

Когда вам необходимо ввести информацию, вы выделяете ее (>>) из входного потока cin и заносите в некоторую переменную — например, ivalue. Для вывода информации вы берете копию информации из переменной ivalue и вставляете ее (<<) в выходной поток cout.

Последней, но немаловажной, особенностью операций вставки и выделения является их дополнительное преимущество — малый размер результирующего кода. Универсальные функции ввода/вывода printf() и scanf() помимо своего кода включают в исполняемый модуль программы много зачастую ненужной информации. В C++, напротив, компилятор включает только те процедуры, которые действительно нужны.

Операция вставки << не генерирует автоматически символ перевода строки. При необходимости это можно делать непосредственно, включая в программу символ \n или endl.

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

 

18. От файла STREAM.H к файлу IOSTREAM.H. Операции и методы классов. Вывод символов в C++. Преобразование системы счисления в C++. Форматирование строк в C++. Форматирование чисел в C++. Файловый ввод и вывод в C++.

В библиотеке iostream предопределен набор операций для выполнения считывания и записи встроенных типов данных. Также библиотека обеспечивает пользовательские расширения для обработки классов. Базовые операции ввода обеспечивает класс istream, а операции вывода — класс ostream. Двунаправленный ввод/вывод поддерживается классом iostream, который является производным от istream и ostream.

Для пользователя предопределены четыре потоковых объекта:

cin Объект класса istream, связанный со стандартным вводом
cout Объект класса ostream, связанный со стандартным выводом
сеrr Небуферизированный выходной объект класса ostream, связанный со стандартным устройством ошибок
clog Буферизированный выходной объект класса ostream, связанный со стандартным устройством ошибок

В любую программу, использующую библиотеку iostream, должен быть включен заголовочный файл iostream.h. Новую библиотеку ввода/вывода можно также использовать для выполнения файловых операций ввода и вывода. Связать файл с программой можно при помощи описаний трех следующих классов:

fstream Производный от iostream, связывает файл с приложением для считывания и записи
ifstream Производный от istream, связывает файл с приложением только для считывания
ofstream Производный от ostream, связывает файл с приложением только для записи

Для того, чтобы принимать аргументы любых встроенных типов данных, включая char *, операции выделения >> и вставки << были модифицированы. Их также можно расширить, и они будут принимать в качестве параметров классы. В новой версии каждый объект класса iostream имеет переменные, управляющие операциями форматирования. Флагами статуса формата можно манипулировать при помощи функций setf() и unsetf().

Флаг Значение
ios:: showbase Отображает числовые константы в формате, который может читать компилятор C++
ios:: showpoint Отображает числа float с точкой и нулями в конце
ios:: dec(oct, hex) Форматирует числа в десятичной (8ричн., 16ричн.) системе счисления (система счисления по умолчанию)
ios:: fixed Показывает числа float в фиксированном формате
ios:: showpos Отображает знак "плюс" (+) перед положительными числами
ios:: skipws Пропускает пробельные символы на входе
ios:: left Выравнивает слева все значения (дополняя справа указанным заполняющим символом)
ios: right Выравнивает справа все значения (дополняя слева указанным заполняющим символом, опция по умолчанию)
ios:: internal Добавляет заполняющие символы после любого знака или указателя системы счисления до начала числа
ios:: unitbuf Заставляет ostream::osfx очищать поток после каждой операции вставки (по умолчанию сеrr буферизируется)
ios::stdio Заставляет ostream::osfx очищать stdout и stderr после каждой вставки

cout.setf (ios:: uppercase); // включить заглавные

cout << hex << ivalue;

cout.unsetf(ios:: uppercase); // выключить заглавные

В нынешней библиотеке печатается сама символьная переменная. Если же нужно получить ASCII-код, то используется такой оператор: cout << (int)c;

Есть два способа для вывода значения в разных системах счисления: cout << hex << ivalue; и cout.setf(ios::hex, ios::basefield);

cout << ivalue;

Переход к некоторому другому основанию выполняется при помощи функции unsetf(): cout.unsetf(ios::hex, ios::basefield);

Для форматирования строки можно объявить массив символов, а затем выбрать необходимый формат вывода при распечатке буфера строки:

pszpadstring38[38 + INULL_TERMINATOR];

ostrstream(pszpadstring38,sizeof(pszpadstring38)) << " " << psz1;

Метод класса ostrstream() является частью файла strstream.h и имеет три параметра: указатель на массив символов, размер массива и выводимая информация. Для выравнивания вправо этот оператор в начало строки psz1 добавляет пробелы.

Можно без затруднений форматировать числовые данные: выравнивать вправо или влево, менять точность и формат, добавлять заполняющие символы, управлять знаком. Здесь выводится значение а, выравненное влево в поле шириной 20 символов и с нулями в конце:

cout.width(20);cout.setf(ios:: left);cout.fill ('0');cout << а;

Если в приложении нужно создать файл для ввода и вывода, то в него необходимо включить заголовочный файл fstream.h (файл fstream.h включает в себя iostream.h). Классы ifstream и ofstream являются производными от istream и ostream и наследуют операции выделения и вставки, соответственно. В примере показано, как объявить файл для считывания и для записи при помощи ifstream и ofstream, соответственно:

#include <iostream>

using namespace std;

#include <fstream.h>

void main(void)

{ char c; ifstream ifsin("D:\\Programming\\Programming 02\\text.in", ios::in);

if(!ifsin) cerr << "\nUnable to open 'text.in' for input.";

ofstream ofsout("D:\\Programming\\Programming 02\\text.in",ios::out);

if(!ofsout) cerr << "\nUnable to open 'text.out' for output.";

while(ofsout && ifsin.get(c)) ofsout.put(c);

ifsin.close(); ofsout.close();cout << "\n\n";

 

ios:: in Открыть для считывания

ios:: out Открыть для записи

ios:: ate Искать конец после создания файла

ios:: trunc Если файл существует, то он очищается

ios:: noreplace Открыть только несуществующий файл

Позиционирование для всех типов класса iostream можно осуществлять при помощи методов класса seekg() или seekp(), которые могут устанавливаться на абсолютный адрес в файле или смещаться на заданное число байт от конкретного положения. Оба метода, seekg() (установить или считать положение указателя считывания) и seekp() (установить или читать положение указателя записи), могут иметь один или два аргумента. Если используется один параметр, то iostream устанавливается в заданное положение указателя; если два — вычисляется относительное положение.

19. Условные признаки файлов в C++. Опрос и установка состояния потока. Ошибки потоков. Переадресация ввода-вывода. Резидентные в памяти потоки.

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

Методы функций Действие
eof() Возвращает ненулевое значение при достижении конца файла
fail() Возвращает ненулевое значение, если операция завершена
bad() Возвращает ненулевое значение, если возникла ошибка
good() Возвращает ненулевое значение, если отсутствуют установленные разряды
rdstate() Возвращает текущее состояние потока
clar() Устанавливает состояние потока (int=0)

Эти методы классов можно использовать при реализации различных алгоритмов для определения конкретных состояний ввода/вывода и для большей читаемости программы:

Класс ios поддерживает информацию о состоянии потока после каждой операции ввода-вывода. Текущее состояние потока хранится в объекте типа iostate, который объявлен следующим образом:

typedef int iostate; Установить нужное состояние можно с помощью функции setsfate(): void setstate(iostate state);


Дата добавления: 2015-12-08; просмотров: 146 | Нарушение авторских прав



mybiblioteka.su - 2015-2024 год. (0.015 сек.)