Читаем Thinking In C++. Volume 2: Practical Programming полностью

Each public function in a class essentially forms a contract with the user; if you pass it certain arguments, it will perform certain operations and/or return a result. The same contract must hold true in derived classes; otherwise the expected "is-a" relationship between derived and base classes is violated. Since exception specifications are logically part of a function’s declaration, they too must remain consistent across an inheritance hierarchy. For example, if a member function in a base class says it will only throw an exception of type A, an override of that function in a derived class must not add any other exception types to the specification list, because that would result in unexpected exceptions for the user, breaking any programs that adhere to the base class interface. You can, however, specify fewer exceptions or none at all, since that doesn’t require the user to do anything differently. You can also specify anything that "is-a" A in place of A in the derived function’s specification. Here’s an example.

// C01:Covariance.cpp

// Compile Only!

//{-msc}

#include

using namespace std;

class Base {

public:

  class BaseException {};

  class DerivedException : public BaseException {};

  virtual void f() throw (DerivedException) {

    throw DerivedException();

  }

  virtual void g() throw (BaseException) {

    throw BaseException();

  }

};

class Derived : public Base {

public:

  void f() throw (BaseException) {

    throw BaseException();

  }

  virtual void g() throw (DerivedException) {

    throw DerivedException();

  }

};

A compiler should flag the override of Derived::f( ) with an error (or at least a warning) since it changes its exception specification in a way that violates the specification of Base::f( ). The specification for Derived::g( ) is acceptable because DerivedException "is-a" BaseException (not the other way around). You can think of Base/Derived and BaseException/DerivedException as parallel class hierarchies; when you are in Derived, you can replace references to BaseException in exception specifications and return values with DerivedException. This behavior is called covariance  (since both sets of classes vary down their respective hierarchies together). (Reminder from Volume 1: parameter types are not covariant—you are not allowed to change the signature of an overridden virtual function.).

<p>When <emphasis>not</emphasis> to use exception specifications</p>

If you peruse the function declarations throughout the Standard C++ library, you’ll find that not a single exception specification occurs anywhere! Although this might seem strange, there is a good reason for this seeming incongruity: the library consists mainly of templates, and you never know what a generic might do. For example, suppose you are developing a generic stack template and attempt to affix an exception specification to your pop function, like this:

T pop() throw(logic_error);

Since the only error you anticipate is a stack underflow, you might think it’s safe to specify a logic_error or some other appropriate exception type. But since you don’t know much about the type T, what if its copy constructor could possibly throw an exception (it’s not unreasonable, after all)? Then unexpected( ) would be called, and your program would terminate. The point is that you shouldn’t make guarantees that you can’t stand behind. If you don’t know what exceptions might occur, don’t use exception specifications. That’s why template classes, which constitute 90 percent of the Standard C++ library, do not use exception specifications—they specify the exceptions they know about in documentation and leave the rest to you. Exception specifications are mainly for non-template classes.

<p>Exception safety</p>

In Chapter 7 we’ll take an in-depth look at the containers in the Standard C++ library, including the stack container. One thing you’ll notice is that the declaration of the pop( ) member function looks like this:

void pop();

You might think it strange that pop( ) doesn’t return a value. Instead, it just removes the element at the top of the stack. To retrieve the top value, call top( ) before you call pop( ). There is an important reason for this behavior, and it has to do with exception safety, a crucial consideration in library design.

Suppose you are implementing a stack with a dynamic array (we’ll call it data and the counter integer count), and you try to write pop( ) so that it returns a value. The code for such a pop( ) might look something like this:

template

T stack::pop() {

  if (count == 0)

    throw logic_error("stack underflow");

  else

    return data[--count];

}

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

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

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

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

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

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

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

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

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