Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры по ООП.doc
Скачиваний:
31
Добавлен:
25.09.2019
Размер:
1.04 Mб
Скачать

47.Методы ввода-вывода.

Операции ввода-вывода для файловых потоков могут быть реализованы теми же средствами, что и для других видов потоков: перегрузкой операторов, использованием ранее описанных методов get(), getline(); read(), put(), write(). При этом для организации ввода-вывода в двоичных файлах обычно используются методы read() и write().

После того как ваша программа открыла файл для ввода или вывода, она может читать или писать данные, используя операторы извлечения (>>) и вставки (<<).

Ваши программы могут выполнять ввод или вывод символов в файл или из файла, используя функции get и put.

Ваши программы могут читать из файла целую строку, используя функцию getline.

Большинство программ читают содержимое файла, пока не встретится конец файла. Ваши программы могут определить конец файла с помощью функции eof.

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

Если вашим программам необходимо вводить или выводить такие данные, как структуры или массивы, они могут использовать методы read и write.

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

input_file.read(buffer, sizeof(buffer)) ;

output_file.write(buffer, sizeof(buffer));

Функция write обычно получает указатель на символьную строку. Символы (char *) представляют собой оператор приведения типов, который информирует компилятор, что вы передаете указатель на другой тип.

Пример: программа копирования одного файла в другой. Имена файлов берутся из командной строки программы:

#include <fstream.h>

#include <libc.h>

void error(char* s, char* s2 ="")

{

cerr << s << ' ' << s2 << endl;

exit(1);

}

void main(int argc, char **argv)

{

if (argc != 3) error("Неверное количество аргументов");

ifstream from(argv[1]);

if (!from) error("Невозможно открыть входной файл",argv[1]);

ostream to(argv[2]);

if (!to) error("Невозможно открыть выходной файл",argv[2]);

char ch;

while (from.get(ch)) to.put(ch);

if (!from.eof() || to.bad())

error("Ошибка ввода-вывода при копировании файлов");

}

Более быстрый вариант программы (для сокращения записи убраны проверки правильности выполнения операций):

void main(int argc, char **argv)

{

ifstream from(argv[1],ios::in|ios::binary);

ostream to(argv[2],ios::out|ios::binary);

char buf[512];

from.read(buf,512);

while (! from.eof()) {

int len = from.gcount(); // количество прочитанных символов

to.write(buf,len);

}

}

13.Преобразование типов в производных классах.

Если производный класс derived имеет открытый базовый класс base, то указатель на derived можно присваивать переменной типа указатель на base не используя явное преобразование типа. Обратное преобразование, указателя на base в указатель на derived, должно быть явным. Например:

class base { /* ... */ };

class derived : public base { /* ... */ };

derived m;

base* pb = &m // неявное преобразование

derived* pd = pb; // ошибка: base* не является derived*

pd = (derived*)pb; // явное преобразование

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

Обратное неверно.

Будь base закрытым базовым классом класса derived, неявное преобразование derived* в base* не делалось бы. Неявное преобразование не может в этом случае быть выполнено, потому что к открытому члкну класса base можно обращаться через указатель на base, но нельзя через указатель на derived:

class base {

int m1;

public:

int m2; // m2 - открытый член base

};

class derived : base {

// m2 НЕ открытый член derived

};

derived d;

d.m2 = 2; // ошибка: m2 из закрытой части класса

base* pb = &d // ошибка: (закрытый base)

pb->m2 = 2; // ok

pb = (base*)&d // ok: явное преобразование

pb->m2 = 2; // ok

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