№30. Особенности сортировки файлов
Особенность сортировки файлов в том, что на самом деле, несмотря на методы произвольного доступа мы не можем обратиться к необходимому адресу напрямую. Поэтому время доступа к разным частям файла отличается. Кроме того операции чтения-записи файлов гораздо медленнее аналогичных для оперативной памяти, поэтому знакомые нам алгоритмы применить не получится. Кроме того, файлы могут быть столь велики, что не поместятся в опративную память, поэтому отсортировать их в оперативной памяти и вернуть на место может не получиться.
Все это приводит к тому, что для сортировки файлов применяют особые методы, при которых файл делится на части, которые помещаются в оперативную память, и с ними начинается мегашаманство.
Мы изучаем три метода шаманства:
- Сортировка файлов слиянием
- Осциллирующая сортировка
- Многофазная сортировка
О них подробнее в других вопросах.
№29. Прямой доступ к отдельным записям в файлах
Бывает что и такое нужно.
Для этого пользуются функции seekg() для установки курсора чтения и seekp() для установки курсора записи.
У этих функций два параметра - смещение курсора и точка отсчета:
myFStr.seekp(смещение, точка отсчета);
//В качестве точки отсчета может выступать
//одна из трех констант:
ios::beg //начало файла
ios::cur //текущее положение курсора
ios::end //конец файла
Пример:
#include <fstream.h>
fstream myFStr;
myFStr.open(file);
char buf;
myFStr.seekg(12, ios::beg);
myFstr.get(buf);
cout<<"12й символ - "<<buf<<endl;
myFStr.seekp(12, ios::beg);
myFStr.put('');
cout<<"Теперь 12й символ - нулевой))гыгы"<endl;
myFStr.close();
№27, 28. Файлы и потоки; методы открытия файлов для обмена информацией
Ахха! Вот мы и подошли к весьма простой, но ОЧЕНЬ шаманской теме, ибо файловые потоки без бубна работайут крайне редко (в моих кривых руках))
Кстати, вообще говоря любая работа с файлами подразумевает использование потоков. И вообще, потоками реализован весь ввод-вывод в C/C++, но на лабах “потоковой” называется работа с файлами через библиотеку fstream.
Итак.
Итак, для начала нужно как минимум подключить библиотеку fstream.h:
#include <fstream.h>
Потом создать файловый поток для необходимого файла:
ifstream myFStr; //для чтения
ofstream myFStr; //для записи
fstream myFStr; //для любых операций
Потом нужно связать поток с нужным файлом:
myFStr.open(filename [, метод открытия]);
Методы открытия:
ios::app
ios::ate
ios::binary
ios::in
ios::out
ios::trunc
Их можно комбинировать логической операцией “ИЛИ”, т.е.
myFStr.open(filename, ios::in | ios::out);
//откроет файл filename для чтения и записи
Но в 99% случаев вам это не понадобится, так как этот параметр задан по умолчанию (для каждого типа потоков соответствующий) и его можно опустить:
myFStr.open(filename);
Потом, по-хорошему, нужно проверить, открылся ли файл:
if (!myFSTR)
{
//Файл не открылся, паникуем
}
Еще можно проверить, открылся ли файл, вызвав функцию is_open();
if (!myFSTR.is_open())
{
//Файл не открылся, паникуем
}
Так типа корректнее.
В общем, после всех этих манипуляций мы получили рабочий файловый поток, открытый как нам надо.
Можем делать с ним все что хочется с помощью операций потокового ввода-вывода (<< >>)
Типа:
myFStr<<"Тостеры"<<39,95<<endl;
myFStr<<"Миксеры"<<24,95<<endl;
а потом
char item[20];
float cost;
myFStr>>item>>cost;
cout<<item<<" "<<cost<<endl;
myFStr>>item>>cost;
cout<<item<<" "<<cost<<endl;
Теперь все это надо закрыть:
myFStr.close();
Вот
Все
Упарился
№26. Основные правила построения абстрактных классов
Семь заповедей Козлова (из странных лекций, с исправленными ошибками [по возможности])
- Виртуальная функция - функция, которую производный класс может переопределить (не перегрузить)
- Реализация виртуальных функций класса (??? бред какой-то, это все, что написано в этом пункте)
- При использовании виртуальных функций можно не переопределять их в наследниках, так ка одна реализация уже существует.
- В общем случае функции-члены следует делать виртуальными
- Конструкторы не могут быть виртуальными.
- Деструкторы могут быть виртуальными, чтобы потомки корректно освобождали виртуальную память
- Тип виртуальной функции менять нельзя
№24. Абстрактные классы и их применение
Абстрактный класс (класс-интерфейс) - класс, содержащий хотя бы один чисто виртуальный метод.
Используется для того, чтобы объявить способ обращения к методам производных классов, что позволяет использовать для хранения объектов производных классов унифицированный указатель на базовый класс (например, можно хранить объекты разных классов в одном массиве) .
№23. Виртуальные методы классов
Методы, объявленные в базовом классе, которые могут быть переопределены в классе-наследнике.
Объявляются ключевым словом virtual.
Если нет возможности создать адекватную реализацию метода в базовом классе - используют чисто виртуальные методы, т.е. методы, которые не определены а лишь объявлены в базовом классе. Объявляется также, но с приравниванием к нулю. Пример:
virtual void some(int, char); //Виртуальный метод
virtual void some(int, char)=0; //Чисто виртуальный метод
№22, 25. Раннее и позднее связывание классов
Итак, в промежутках между анекдотами про “не с глаголами”, Козлов очень невнятно рассказал про связывание классов.
Насколько я понял, он подразумевает, что в данном случае связывание будет происходить между интерфейсным классом и конкретной реализацией. Т. е. если мы создаем абстрактный класс interf, мы можем использовать указатель типа interf* для работы с любыми потомками класса interf. Соответственно, не всегда во время компиляции можно сказать, объект какого класса будет находиться в памяти по указателю. Этот случай называется поздним связыванием или связыванием “времени выполнения”. Если же все известно заранее - связывание раннее. Пример:
class interf
{
public:
virtual int getlength()=0;
}
class square:interf
{
private:
int side;
public:
int getlength()
{
return side;
}
}
class rectangle:interf
{
private:
int sideA, sideB;
public:
int getlength()
{
return (sideA>sideB?sideA:sideB);
}
}
//статическое (раннее) связывание
interf* staticPTR = new square();
interf* dynamicPTR;
cout>>"Input q if it's square";
char isquad;
cin>>isquad;
//динамическое (позднее) связывание
if (isquad)
{
ptr = new square();
}
else
{
ptr = new rectangle;
}
//еще инфа
№21. Типы наследования классов
Наследование может быть открытым (class child: public parent), закрытым (class child: private parent), защищенным (class child: protected parent) и множественным (class child: parent1, parent2)
Суть:
открытое наследование (public) - все открытые и защищенные члены базового класса становятся открытыми и защищенными членами производного класса. При этом закрытые члены базового класса производным не наследуются.
закрытое наследование (private) - все открытые и защищенные члены базового класса становятся закрытыми членами производного класса.
защищенное наследование (protected) - все открытые и защищенные члены базового класса становятся защищенными членами производного класса.
множественное наследование - производный класс одновременно наследует свойства нескольких базовых классов.
№20. Доступность членов класса в классах-наследниках
public и protected - доступны, private - нет.
That’s all.
№19. Отношения классов
Отношения между двумя классами могут быть родственными (родитель-потомок) дружественными (friend) или нейтральными.
Знаете, что можно еще сказать по этому вопросу - пишите в коменты, буду благодарен.
№18. Принципы объектно-ориентированного программирования
№17. Функции потокового ввода и вывода объектов
Ничего сложного нет, но напомню прототипы:
ostream& operator<<(ostream&, наш_класс);
istream& operator>>(наш_класс, istream&);
Кажется, так. Но! Я не уверен насчет порядка параметров в операторе>>.
Гуру, пишите в каментах, если я не прав.
№16. Функции – друзья класса
Они есть. Да.
А еще они не являются членами класса, но все равно имеют доступ к защищенным членам класса. Вооот.
Собственно все.
Объявляются они очень просто.
Нужно в классе поместить прототип функции, поставив перед ним ключевое слово friend
№13,14. Операторные функции – члены/не члены класса
Перегрузить операторную функцию можно несколькими способами.
1. Как обычную функцию
2. Как функцию-член класса, для которого происходит перегрузка
3. Как функцию, дружественную к этому классу
Бинарный оператор-член класса вызывается объектом, стоящим слева от оператора, что может вызвать проблемы, когда нужный нам класс стоит справа от оператора, т.е.:
obj + 100 //все работает, так как в объекте obj определена операторная функция-член operator+
100 + obj //не работает, так как в классе int не ереопределен оператор +, принимающий параметром объекты нужного типа
Дружественная функция решает эту проблему, так как получает в качестве параметров и число 100 и объект obj
Недружественная функция вобще не катит, по причине отсутствия доступа к закрытым членам класса, а стало быть неудобством реализации.
№12. Объекты как параметры функций
Ответ - да))
№11. Встроенные методы классов
Встроенные методы класса - методы, вызов которых при компиляции заменяется его телом.
Для объявления метода встроенным необходимо укзать перед его названием ключевое слово inline
№10. Статические поля данных и методы классов.
Статические поля данных - поля, значения которых общие для всех объектов данного класса.
Статические методы - методы, которые могут работать со статическими данными.
И то и другое объявляется ключевым словом static
№09. Деструкторы классов
Деструктор класса - специальный метод класса, который вызывается при уничтожении объекта.
Если деструктор не определяется в классе, любой компилятор неявно создает деструктор по умолчанию, который занимается очисткой памяти, занятой объектом.
Чтобы определить свой деструктор надо объявить в классе метод с именем именем типа ~имя_класса:
class cSample
{
private: int variable;
public:
void cSample(); /*конструктор без параметра,
будет вызываться при выполнении
конструкций типа cSample sObj;*/
void ~cSample(); //деструктор
}
Определять деструктор можно как в теле класса (компилятор обработает его как inline) так и вне его.
№08. Обеспечение доступа к защищённым членам класса.
Доступ к защищенным членам класса нужно обеспечивать посредством открытых методов [вместо obj.var - obj.getvar() или obj.putvar()]
Это главный принцип ООП - инкапсуляция.
№07. Типы защищённости членов класса
Члены класса могут иметь один из трех типов защищенности:
private - доступ к члену класса ограничен методами класса и дружественными функциями.
protected - то же самое, что и private, но доступ к такому члену имеют и классы-наследники.
public - обращения допускаются из любого кода.
№06. Конструкторы классов.
Конструктор класса - специальный метод класса, который вызывается при инициализации объекта.
Если конструктор не определяется в классе, любой компилятор неявно создает конструктор по умолчанию, который занимается выделением места под объект.
Чтобы определить свой конструктор надо объявить в классе метод с именем этого класса и любыми необходимыми параметрами. Можно объявить несколько конструкторов с разным набором парамтером (перегрузка конструкторов).
class cSample {private: int variable;
public:
void cSample(); /*конструктор без параметра,
будет вызываться при выполнении
конструкций типа cSample sampObject; */
void cSample(int); //конструктор с параметром
}
№04,05 Классы и объекты; члены класса – методы и поля.
См. статью
№02,03. Заголовочные файлы классов; файлы реализации классов.
Вопросы нупские совершенно, но по-видимому тут необходимо сказать, что нужно разделять объявление и определение класса, т.е.
someclass.h: //заголовочный файл класса
class someClass
{
private:
//переменные
int* something = new int[10];
public:
//только заголовки методов
void delete();
int getNumber(char*);
}
someclass.cpp: //файл реализации класса
void someClass::delete()
{
delete []something;
}
void someClass::getNumber(char* str)
{
return strlen(str);
}
№01. Структуры и классы языка C++
Статья об объектно-ориентированном подходе к программированию.
К сожалению про Паскаль, но сам подход ООП объясняется крайне доходчиво.