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




>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);