You are on page 1of 48

Лекция 8

Standard Template Library


IRON'S IRON.' BUT IS IT? Or is iron made from other things?
According to Empedocles, an ancient Greek, everything in the universe was a combination of four
ingredients: earth, air, fire, and water. Set light to a stick and it burns (showing that it contains fire),
gives off smoke (showing that it contains air), exudes bubbly liquids (showing that it contains
water), and leaves a dirty heap of ash behind (showing that it contains earth). As a theory, it was a
bit too simple-minded to survive for long, a couple of thousand years at best. Things moved more
slowly in those days, and Europe, at least, was more interested in making sure that the peasants
didn't get above their station and copying out bits of the Bible by hand in as laborious and colourful
a manner as possible.
Science of Discworld by Terry Pratchett, Ian Stuart, Jack Cohen, WE ARE STARDUST
Предварительная
информация
explicit
The explicit keyword prevents implicit type casting.
So, if there is no explicit type conversion, the compiler
will generate an error.
explicit
class cl2
{cl2(int);//Not an explicit constructor.

};
cl2 v=2;
// Creates an object, than assigns
// the value.
explicit
class cl2
{explicit cl2(int);

};
cl2 v=2; // Not allowed.
cl2 v=cl2(2); // Ok.
namespace
file1.hpp
int value(){ return 5;}
file2.hpp
const double pi=3.1416
int value(){ return 2*pi;}

file3.cpp
#include <file1.hpp>
#include <file2.hpp>
// What the compiler should call here?
int i=value(); 
namespace
file1.hpp
namespace space1
{
  int value(){ return 5;}
}
file2.hpp
namespace space2
{
  const double pi=3.1416
  int value(){ return 2*pi;}
}
namespace
file3.cpp
#include <file1.hpp>
#include <file2.hpp>

int i=space1::value(); // file1.hpp
int j=space2::value(); // file2.hpp
namespace
file3.cpp
#include <file1.hpp>
#include <file2.hpp>

using namespace space1;
int i=value(); // file1.hpp
using namespace space2;
int j=space2::value(); // file2.hpp
// Compiler generates an error without 
space2:: , for it don’t understans what 
to call.
Наконец,
namespace std
{
Библиотека ввода/вывода
Консольный ввод/вывод
Следующие классы работают с консолью, то есть
клавиатурой и текстовым выводом на экран.
class istream
Форматированный ввод
istream& operator>> (bool& val);
istream& operator>> (short& val);
istream& operator>> (unsigned short& val);
istream& operator>> (int& val);
istream& operator>> (unsigned int& val);
istream& operator>> (long& val);
istream& operator>> (unsigned long& val);
istream& operator>> (long long& val);
istream& operator>> (unsigned long long& val);
istream& operator>> (float& val);
istream& operator>> (double& val);
istream& operator>> (long double& val);
istream& operator>> (void*& val);
class istream
Неформатированный ввод
single character
int get();
istream& get (char& c);
c-string
istream& get (char* s, streamsize n);
istream& get (char* s, streamsize n, 
char delim);

istream& getline(char* s, streamsize n);


istream& getline(char* s, streamsize n,
char delim);
class ostream
Форматированный вывод
ostream& operator<< (bool val);
ostream& operator<< (short val);
ostream& operator<< (unsigned short val);
ostream& operator<< (int val);
ostream& operator<< (unsigned int val);
ostream& operator<< (long val);
ostream& operator<< (unsigned long val);
ostream& operator<< (long long val);
ostream& operator<< (unsigned long long val);
ostream& operator<< (float val);
ostream& operator<< (double val);
ostream& operator<< (long double val);
ostream& operator<< (void* val);
class ostream
Неформатированный вывод
single character

istream& put (char& c);
c-string
<< only!
Потоки
Для консольных программ определено несколько
переменных для ввода и вывода
cin – консольный ввод (клавиатура)
cout – консольный вывод (черное окошко)
cerr – поток ошибок (окно компилятора с
ошибками)
clog – поток журнала (там, где у компилятора
пишется запуск/остановка приложения, загрузка
библиотек, …)
Консольный ввод/вывод
// istream::getline example
#include <iostream>     // std::cin, std::cout

int main () {
char name[256], title[256];
std::cout << "Please, enter your name:";
std::cin.getline (name,256);
std::cout << «Enter your favorite movie:";
std::cin.getline (title,256);
std::cout << name << "'s favorite movie is " << 
title;
return 0;
}
Консольный ввод/вывод
Конструкторы
ifstream();
explicit ifstream (const char* filename, 
ios_base::openmode mode = ios_base::in);
explicit ifstream (const string& 
filename, ios_base::openmode mode = 
ios_base::in);
ifstream (const ifstream&) = delete;
ifstream (ifstream&& x);
class ifstream
Режимы открытия файлов.
File open for reading: the internal stream buffer
in input
supports input operations.
File open for writing: the internal stream buffer
out output
supports output operations.
Operations are performed in binary mode
binary binary
rather than text.
ate at end The output position starts at the end of the file.
All output operations happen at the end of the
app append
file, appending to its existing contents.
Any contents that existed in the file before it is
trunc truncate
open are discarded.
class ifstream
Открытие и закрытие файлов
void open (const   char* filename,  
ios_base::openmode mode = ios_base::in);
void open (const string& filename,  
ios_base::openmode mode = ios_base::in);
void close();
bool good() const;
bool eof() const;
ifstream/ofstream classes
Чтение двоичных данных
istream& read (char* s, streamsize n);
Запись двоичных данных
ostream& write (const char* s, 
streamsize n);
class ifstream
Позиционирование в открытом классе
istream& seekg (streampos pos);
istream& seekg (streamoff off, 
ios_base::seekdir way);
ios_base::beg beginning of the stream
ios_base::cur current position in the stream
ios_base::end end of the stream
// Returns the current position.
streampos tellg();
ifstream (Пример)
// reads a file into memory
#include <iostream>     // std::cout
#include <fstream>      // std::ifstream
int main () {
  std::ifstream is ("test.txt", 
std::ifstream::binary);
  if (is) {
    is.seekg (0, is.end);
    int length = is.tellg();
    is.seekg (0, is.beg);
ifstream (Пример)
    char * buffer = new char [length];
    is.read (buffer,length);
    is.close();
    std::cout.write (buffer,length);
    delete[] buffer;
  }
  return 0;
}
ifstream (Пример)
    int *buffer=
         new int [length/sizeof(int)];
    is.read ((char*)buffer,length);
    is.close();

    delete [] buffer;
  }
  return 0;
}
Сериализация объектов
class Unit
{
  UnitKind getKind() { return kind; };
  virtual void write(ofstream &file)=0;
  virtual void read(ifstream &file)=0;  
  virtual void move()=0;
 private:
  UnitKind kind;
};
Сериализация объектов
class Infantry: Unit
{

  virtual void write(ofstream &file);
  virtual void read(ifstream &file);  
  virtual void move();
 private:
  float shield, force, health;
};
Сериализация объектов
void Infantry::write(ofstream &file)
{
 file << shield << ”, ” << force
     << ”, ” << health << ”\n”;
};
// Case of text file.
void Infantry::read(ifstream &file)
{char c;
 file >> shield >> c >> force >> c 
      >> health >> c;
};
Сериализация объектов
void Infantry::write(ofstream &file)
{
file.write((char*)&shield,sizeof(float))
;
file.write((char*)&force,sizeof(float));
file.write((char*)&health,sizeof(float))
;
};
// Case of binary file (the same name).
void Infantry::read(ifstream &file)
{file.read((char*)&shield,sizeof(float))
;
Сериализация объектов
class UnitCollection
{

 void write(std::string filename);
 void read (std::string filename);

};
Сериализация объектов
… ::write(std::string filename)
{std::ofstream ofile(filename);
 int tmp;
 ofile.write((char*)&ucnt, sizeof(int));
 for( int i=0; i<ucnt; i++ )
 {tmp=units[i]­>getKind()
  ofile.write((char*)&tmp, sizeof(int));
  units[i]­>write(ofile);
 }
}
Сериализация объектов
… ::write(std::string filename)
{std::ofstream ofile(filename);
 int tmp;
 ofile.write((char*)&ucnt, sizeof(int));
 for( int i=0; i<ucnt; i++ )
 {tmp=units[i]­>getKind()
  ofile.write((char*)&tmp, sizeof(int));
  units[i]­>write(ofile);
 }
} // Why don’t I close the file?
Сериализация объектов
… ::read(std::string filename)
{std::ifstream ifile(filename);
 int tmp;
 ifile.read((char*)&ucnt, sizeof(int));
 units=new Unit*[ucnt];
 for( int i=0; i<ucnt; i++ )
 {ifile.read((char*)&tmp, sizeof(int));
  if(tmp==utInf) units[i]=new Infantry;
else if(tmp==utChiv)units[i]=new Chival;
  …
  units[i]­>read(ifile);
} }
Однако…
Приведенный код нехорош.
На свете существуют виртуальные функции, но при
этом вызываем их явно.
И что делать?
Надо создать виртуальные функции чтения и
записи у Unit и переопределить их у дочерних
классов. Но как понять кого читать?
Можно создать функцию фабрики классов, которая
будет возвращать Unit* на объект правильного
типа, принимая при этом параметр, указывающий
на тип объекта. А тип объекта можно читать из
файла.
Сериализация объектов
class Unit
{// A Unit can read and write its type.
  UnitKind getKind() { return kind; };
  void writeKind(ofstream &file);
  UnitKind readKind(ifstream &file);
  virtual void write(ofstream &file)=0;
  virtual void read(ifstream &file)=0;  
  virtual void move()=0;
 private:
  UnitKind kind;
};
Сериализация объектов
class Infantry: public Unit
{

  virtual void write(ofstream &file);
  virtual void read(ifstream &file);  
  virtual void move();
 private:
  float shield, force, health;
};
Сериализация объектов
// Writing and reading a binary file.
void Infantry::write(ofstream &file)
{
file.write((char*)&shield,sizeof(float))
;
file.write((char*)&force,sizeof(float));
file.write((char*)&health,sizeof(float))
;
};
void Infantry::read(ifstream &file)
{file.read((char*)&shield,sizeof(float))
;
Функция фабрики классов
Unit *unitFactory(UnitKind kind)
{
 if(kind==utInf) return new Infantry;
 if(kind==utChiv) return new Chival;
...
//Hope there will be an error somewhere.
 return NULL; 
}
Функция фабрики классов
Должна существовать только одна такая функция
для группы классов. Ее не надо копировать.
При появлении нового производного класса
достаточно внести изменения лишь в одно место.
Функция фабрики классов
ofstream &operator << (ofstream &file, 
Unit *data)
{
 data­>writeKind(file);
 data­>write(file);
 return file;
}
Функция фабрики классов
ifstream &operator >> (ifstream &file, 
Unit *&data)
{UnitKind tmpKind;

 file.read((char*)&tmpKind, 
           sizeof(UnitKind));
 data=unitFactory(tmpKind);
 data­>read(file);
 return file;
}
Функция фабрики классов
class UnitCollection
{

 void write(std::string filename);
 void read (std::string filename);

};
Функция фабрики классов
… ::write(std::string filename)
{std::ofstream ofile(filename);

 ofile.write((char*)&ucnt, sizeof(int));
 for( int i=0; i<ucnt; i++ )
  ofile<<units[i];
}
Функция фабрики классов
… ::read(std::string filename)
{std::ifstream ifile(filename);

 ifile.read((char*)&ucnt, sizeof(int));
 units=new Unit*[ucnt];
 for( int i=0; i<ucnt; i++ )
  ifile>>units[i];
}
ifstream class

} // namespace std, part 1.
Quote of the Day

Parents spend two years


teaching their child
to walk and to talk.
Then they spend the next 16
years making them
to sit down and to shut up.