Читаем Стандарты программирования на С++ полностью

Если, как автор класса В, вы хотите разрешить срезку, но не хотите, чтобы она могла происходить по ошибке, для такого случая существует один вариант действий, о котором мы упомянем для полноты изложения, но не рекомендуем использовать его в коде, к которому предъявляется требование переносимости: вы можете объявить копирующий конструктор В как explicit. Это может помочь избежать неявной срезки, но кроме этого запрещает все передачи параметров данного типа по значению (что может оказаться вполне приемлемым для базовых классов, объекты которых все равно не должны создаваться; см. рекомендацию 35).

// Объявляем копирующий конструктор как explicit (у данного

// решения имеется побочное действие, так что требуется

// улучшение этого метода)

class B { // ...

public:

 explicit B(const B& rhs);

};

class D : public B { /* ... */ };

Вызывающий код все равно в состоянии выполнить срезку, если это необходимо, но должен делать это явно:

void Transmogrify(B obj); // Теперь эта функция вообще не

                          // может быть вызвана (!)

void Transmogrify2(const B& obj) // Идиома для намерения в

{                                // любом случае получить

 В b( obj );                     // параметр obj по значению

 // ...                          // (с возможной срезкой)

}

B b;              // Базовые классы не должны быть конкретными

D d;              // (см. рекомендацию 35), но допустим это

Transmogrify(b);  // Должна быть ошибка (см. примечание)

Transmogrify(d);  // Должна быть ошибка (см. примечание)

Transmogrify2(d); // Все в порядке

Примечание: на момент написания данной рекомендации некоторые компиляторы ошибочно допускали один или оба приведенных вызова функции Transmogrify. Эта идиома вполне стандартна, но (пока что) не полностью переносима.

Имеется лучший способ предупреждения срезки, с более высокой степенью переносимости. Пусть, например, функция наподобие Transmogrify в действительности хочет получить полную глубокую копию без информации о действительном производном типе переданного объекта. Более общее идиоматическое решение состоит в том, чтобы сделать копирующий конструктор базового класса защищенным (чтобы функция наподобие Transmogrify не могла случайно его вызвать), а вместо него воспользоваться виртуальной функцией Clone:

// добавление функции Clone (уже лучше, но все еще требуется

// усовершенствование)

class B { // ...

public:

 virtual B* Clone() const = 0;

protected:

 B(const B&);

};

class D : public B { // ...

public:

 virtual D* Clone() const { return new D(*this); }

protected:

 D( const D& rhs ): B(rhs) {/*...*/ }

};

Теперь попытка срезки будет (переносимо) генерировать ошибку времени компиляции, а объявление функции Clone как чисто виртуальной заставляет непосредственный производный класс перекрыть ее. К сожалению, с данным решением все еще связаны две проблемы, которые компилятор не в состоянии обнаружить: в классе, производном от производного, функция Clone может оказаться неперекрытой, а перекрытие Clone может реализовать ее некорректно, так что копия будет не того же типа, что и оригинал. Функция Clone должна следовать шаблону проектирования Nonvirtual Interface (NVI; см. рекомендацию 39), который разделяет открытую и виртуальную природы Clone и позволяет вам использовать ряд важных проверок:

class В { // ...

publiс:

 B* Clone() const { // Невиртуальная функция

  B* р = DoClone();

  assert(typeid(*p) == typeid(*this) &&

   "DoClone incorrectly overridden");

  return p; // проверка типа, возвращаемого DoClone

 }

protected:

 B(const B&);

private:

 virtual B* DoClone() const = 0;

};

Перейти на страницу:

Все книги серии C++ In-Depth

Стандарты программирования на С++
Стандарты программирования на С++

Эта книга поможет новичку стать профессионалом, так как в ней представлен сконцентрированный лучший опыт программистов на С++, обобщенный двумя экспертами мирового класса.Начинающий программист найдет в ней простые и понятные рекомендации для ежедневного использования, подкрепленные примерами их конкретного применения на практике.Опытные программисты найдут в ней советы и новые рекомендации, которые можно сразу же принять на вооружение. Программисты-профессионалы могут использовать эту книгу как основу для разработки собственных стандартов кодирования, как для себя лично, так и для группы, которой они руководят.Конечно, книга рассчитана в первую очередь на профессиональных программистов с глубокими знаниями языка, однако она будет полезна любому, кто захочет углубить свои знания в данной области.

Андрей Александреску , Герб Саттер

Программирование, программы, базы данных

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных