Чтение онлайн

на главную - закладки

Жанры

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Майерс Скотт

Шрифт:

class A {

public:

A; // конструктор по умолчанию

};

class B {

public:

explicit B(int x = 0; bool b = true); // конструктор по умолчанию,

}; // см. далее объяснение

// ключевого слова “explicit”

class C {

public:

explicit C(int x); // это не конструктор по

//
умолчанию

};

Конструкторы классов B и C объявлены в ключевым словом explicit (явный). Это предотвращает их использование для неявных преобразований типов, хотя не запрещает применения, если преобразование указано явно:

void doSomething(B bObject); // функция принимает объект типа B

B bObj1; // объект типа B

doSomething(bObj1); // нормально, B передается doSomething

B bObj(28); // нормально, создает B из целого 28

// (параметр bool по умолчанию true)

doSomething(28); // ошибка! doSomething принимает B,

// а не int, и не существует неявного

// преобразования из int в B

doSomething(B(28)); // нормально, используется конструктор

// B для явного преобразования (приведения)

// int в B (см. в правиле 27 информацию

// о приведении типов)

Конструкторы, объявленные как explicit, обычно более предпочтительны, потому что предотвращают выполнение компиляторами неявных преобразований типа (часто нежелательных). Если нет основательной причины для использования конструкторов в неявных преобразованиях типов, я всегда объявляю их explicit. Советую и вам придерживаться того же принципа.

Обратите внимание, что в предшествующем примере приведение выделено. Я и дальше буду использовать такое выделение, чтобы подчеркнуть важность излагаемого материала. (Также я выделяю номера глав, но это только потому, что мне кажется, это выглядит симпатично.)

Конструктор копирования (copy constructor) используется для инициализации объекта значением другого объекта того же самого типа, а копирующий оператор присваивания (copy assignment operator) применяется для копирования значения одного объекта в другой – того же типа:

class Widget {

public:

Widget; // конструктор по умолчанию

Widget(const Widget& rhs); // конструктор копирования

Widget& operator=(const Widget& rhs); // копирующий оператор присваивания

...

};

Widget w1; // вызов конструктора по умолчанию

Widget w2(w1); // вызов конструктора копирования

w1 = w2; // вызов оператора присваивания

// копированием

Будьте внимательны, когда видите конструкцию, похожую на присваивание, потому что синтаксис «=» также может быть использован для вызова конструктора копирования:

Widget w3 = w2; // вызов конструктора копирования!

К

счастью, конструктор копирования легко отличить от присваивания. Если новый объект определяется (как w3 в последнем предложении), то должен вызываться конструктор, это не может быть присваивание. Если же никакого нового объекта не создается (как в «w1=w2»), то конструктор не применяется и это – присваивание.

Конструктор копирования – особенно важная функция, потому что она определяет, как объект передается по значению. Например, рассмотрим следующий фрагмент:

bool hasAcceptableQuality(Widget w);

...

Widget aWidget;

if (hasAcceptableQuality(aWidget)) ...

Параметр w передается функции hasAcceptableQuality по значению, поэтому в приведенном примере вызова aWidget копируется в w. Копирование осуществляется конструктором копирования из класса Widget. Вообще передача по значению означает вызов конструктора копирования. (Но, строго говоря, передавать пользовательские типы по значению – плохая идея. Обычно лучший вариант – передача по ссылке на константу, подробности см. в правиле 20.)

STL – стандартная библиотека шаблонов (Standard Template Library) – это часть стандартной библиотеки, касающаяся контейнеров (то есть vector, list, set, map и т. д.), итераторов (то есть vector<int>::iterator, set<string>::iterator и т. д.), алгоритмов (то есть for_each, find, sort и т. д.) и всей связанной с этим функциональности. В ней очень широко используются объекты-функции (function objects), то есть объекты, ведущие себя подобно функциям. Такие объекты представлены классами, в которых перегружен оператор вызова operator. Если вы не знакомы с STL, вам понадобится, помимо настоящей книги, какое-нибудь достойное руководство, посвященное этой теме, ведь библиотека STL настолько удобна, что не воспользоваться ее преимуществами было бы непростительно. Стоит лишь начать работать с ней, и вы сами это почувствуете.

Программистам, пришедшим к C++ от языков вроде Java или C#, может показаться странным понятие неопределенного поведения. По различным причинам поведение некоторых конструкций в C++ действительно не определено: вы не можете уверенно предсказать, что произойдет во время исполнения. Вот два примера такого рода:

int *p = 0; // p – нулевой указатель

std::cout << *p; // разыменование нулевого указателя

char name[] = “Daria” // name – массив длины 6 (не забудьте про

// завершающий нуль!)

char c = name[10]; // указание неправильного индекса массива

// порождает неопределенное поведение

Дабы подчеркнуть, что результаты неопределенного поведения невозможно предсказать и что они могут быть весьма неприятны, опытные программисты на C++ часто говорят, что программы с неопределенным поведением могут стереть содержимое жесткого диска. Это правда: такая программа может стереть ваш жесткий диск, но может этого и не сделать. Более вероятно, что она будет вести себя по-разному: иногда нормально, иногда аварийно завершаться, а иногда – просто выдавать неправильные результаты. Мудрые программисты на C++ придерживаются правила – избегать неопределенного поведения. В этой книге во многих местах я указываю, как это сделать.

Поделиться:
Популярные книги

Мастер...

Чащин Валерий
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Мастер...

Жених из гроба

Сотис Майя
1. Гробокопательница
Фантастика:
юмористическое фэнтези
сказочная фантастика
фэнтези
5.00
рейтинг книги
Жених из гроба

Ищу жену с прицепом

Рам Янка
2. Спасатели
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Ищу жену с прицепом

Гримуар тёмного лорда I

Грехов Тимофей
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Гримуар тёмного лорда I

Заклятие предков

Прозоров Александр Дмитриевич
3. Ведун
Фантастика:
фэнтези
альтернативная история
8.49
рейтинг книги
Заклятие предков

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Рота Его Величества

Дроздов Анатолий Федорович
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Рота Его Величества

Экспансия: Сотрудничество. Том 5

Белов Артем
5. Планетарный десант
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Экспансия: Сотрудничество. Том 5

Отверженный III: Вызов

Опсокополос Алексис
3. Отверженный
Фантастика:
фэнтези
альтернативная история
7.73
рейтинг книги
Отверженный III: Вызов

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Возвышение Меркурия. Книга 8

Кронос Александр
8. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 8

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4