Для работы с потоковыми классами ввода/вывода требуется подключение заголовочного файла <iostream>
Замечание. На примере iostream можно наблюдать множественное наследование (ромбовидное)
#include <fstream>
{
    ifstream ifs("a.txt");
    // по-умолчанию открывается как текстовый
    int i, j;
    ifs >> i >> j; // 3_4
} // здесь неявно в деструкторе будет вызван ifs.close()
{
    ofstream ofs("b.txt");
    ofs << i << "  " << j << endl;
    Frac f(1, 2);
    ofs << f;
} // так же вызовется ofs.close()
Благодаря наследованию мы так же можем выводить в файл дроби, аналогично с вводом. То есть нам не надо описывать отдельно ввод/вывод в файл или строку.
Рассмотрим другой пример:
ofstream to1("c.txt", ios_base::app);
while(!ifs.eof())
    getline(ifs, s); // s - имеет тип string
Здесь демонстрируется открытие файла в режиме дозаписи.
В принципе этот код можно заменить на такой:
ofstream to1("c.txt", ios_base::app);
while(ifs)
    getline(ifs, s);
Файлы, строки и т.д. являются разными типами данных, а потоки позволяют унифицировать работу с этими данными.
Ввод в строковый поток осуществляется следующим образом
#include <sstream>
ostringstream os;
os << i << " " << j << frac(1, 2);
cout << os;
const char * cc = os.c_str();
Аналогично выполняется вывод:
#include <sstream>
istringstream is("12 345");
is >> i >> j;
Эта библиотека появилась в C++ не сразу, но достаточно давно.
STL состоит из:
vector<T>, list<T>, set<T>, map<K,V>, queue<T>, stack<T>... ≈10)template<typename ItIn, typename ItOut>
void copy(ItIn b, ItIn e, ItOut b1)
{
    while (b != e)
    {
        *b1 = *b;
        ++b;
        ++b1;
    }
}