Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
При использовании
cin
как входного потока маркер конца файла, который отмечает конец потока, определяется используемой платформой. В Windows для завершения входного потока требуется нажать на Enter, Ctrl-Z, Enter. Чтобы увидеть, что требуется сделать на вашей платформе, проведите эксперименты, но велика вероятность, что будут использоваться эти же клавиши.
Итераторы выходных потоков ведут себя аналогично итераторам потоков ввода. В примере 7.11 я копирую значения из своего vector
в cout
, создав для этого ostream_iterator
, который указывает на cout
, следующим образом.
copy(v.begin(), v.end(), ostream_iterator(cout, ", "));
Аргумент шаблона ostream_iterator
говорит, что записываемые элементы будут иметь тип string
. Первый аргумент конструктора ostream_iterator
— это поток, в который будет производиться запись (и который может быть любым потоком вывода, включая ofstream
и ostringstream
), а второй это используемый разделитель. Это дает удобный способ выводить диапазон значений на стандартный вывод, что я часто делаю при отладке.
Если требуется дополнительное управление внешним видом вывода, например вывод последовательности в квадратных или фигурных скобках или отсутствие последнего разделителя в конце последовательности, то это потребует всего нескольких дополнительных строк кода. Пример 7.12 показывает тело printContainer
и printRange
, первая из которых используется в примерах этой главы.
Пример 7.12. Написание собственной функции печати
#include
#include
#include
#include
#include
using namespace std;
template
void printContainer(const C& c, char delim = ',', ostream& out = cout) {
printRange(c.begin(), c.end(), delim, out);
}
template
void printRange(Fwd first, Fwd last, char delim = ',', ostream& out = cout) {
out << "{";
while (first != last) {
out << *first;
if (++first != last)
out << delim << ' ';
}
out << "}" << endl;
}
int main() {
cout << "Введите набор строк: ";
istream_iterator start(cin);
istream_iterator end;
vector v(start, end);
printContainer(v);
printRange(v.begin(), v.end(), ';', cout);
}
Функция printRange
представляет собой более общий подход, так как оперирует с диапазонами (более подробно это объясняется в рецепте 7.10), но printContainer
более удобна для печати целого контейнера. Имеется множество других способов сделать это. В голову также приходит определение версии operator<<
, которая бы работала с выходным потоком и контейнером, и использование стандартного алгоритма for_each
с собственным функтором для записи элементов в поток.
Глава 8
Классы
8.0. Введение
Эта глава содержит решения проблем, часто возникающих при работе с классами С++. Рецепты по большей части независимы, но разбиты на две части, каждая из которых занимает примерно по половине главы. Первая половина главы содержит решения проблем, которые могут возникнуть при создании объектов классов, таких как использование функции для создания объекта (которая часто называется шаблоном фабрики) или использование конструкторов и деструкторов для управления ресурсами. Вторая половина содержит решения проблем, возникающих после создания объектов, таких как определение типа объекта во время выполнения, а также некоторые методики реализации наподобие создания интерфейса с помощью абстрактного базового класса.
Конечно, классы — это главная особенность С++, которая обеспечивает возможность объектно-ориентированного программирования, и с ними можно выполнять очень много разных действий. Эта глава не содержит рецептов, объясняющих основы классов: виртуальные функции (полиморфизм), наследование и инкапсуляцию. Я полагаю, что вы уже знакомы с этими основными принципами объектно-ориентированного проектирования независимо от используемого языка программирования. Напротив, целью этой главы является описание принципов некоторых механических сложностей, с которыми можно столкнуться при реализации объектно-ориентированного дизайна на С++.
Объектно-ориентированное проектирование и связанные с ним шаблоны проектирования — это обширный вопрос, и имеется большое количество различной литературы на эту тему. В этой главе я упоминаю названия только некоторых шаблонов проектирования, и это шаблоны, для которых возможности C++ обеспечивают элегантное или, возможно, не совсем очевидное решение. Если вы не знакомы с концепцией шаблонов проектирования, я рекомендую прочесть книгу Design Patterns (Addison Wesley), поскольку это полезная вещь при разработке программного обеспечения. Однако для этой главы знание шаблонов проектирования не требуется.
8.1. Инициализация переменных-членов класса
Требуется инициализировать переменные-члены, которые имеют встроенные типы, являются указателями или ссылками.
Для установки начальных значений переменных членов используйте список инициализации. Пример 8.1 показывает, как это делается для встроенных типов, указателей и ссылок.
Пример 8.1. Инициализация членов класса
#include
using namespace std;
class Foo {
public:
Foo() : counter_(0), str_(NULL) {}
Foo(int c, string* p) : counter_(c), str_(p) {}
private:
int counter_;
string* str_;
};
int main() {
string s = "bar";
Foo(2, &s);
}
Переменные встроенных типов следует всегда инициализировать, особенно если они являются членами класса. С другой стороны, переменные класса должны иметь конструктор, который корректно инициализирует их состояние, так что самостоятельно инициализировать их не требуется. Сохранить неинициализированное состояние переменных встроенных типов, когда они содержат мусор, — значит напрашиваться на проблемы. Но в C++ есть несколько различных способов выполнить инициализацию, и они описываются в этом рецепте.
Простейшими объектами инициализации являются встроенные типы. Работать с int
, char
и указателями очень просто. Рассмотрим простой класс и его конструктор по умолчанию.
class Foo {
public:
Foo() : counter_(0), str_(NULL) {}
Foo(int c, string* p) : counter_(c), str_(p) {}
private:
int counter_;
string* str_;
};
Для инициализации переменных-членов используется список инициализации, в результате чего тело конструктора освобождается от этой задачи. Тело конструктора может при этом содержать логику, выполняемую при создании объектов, а инициализацию переменных-членов становится легко найти. Это не столь значительное преимущество по сравнению с присвоением начальных значений в теле конструктора, но все его преимущества становятся очевидны при создании переменных-членов типа класса или ссылок или при попытке эффективного использования исключений.
Читать дальшеИнтервал:
Закладка: