Читаем C++ для начинающих полностью

class stackExcp : public Excp { };

class pushOnFull : public stackExcp {

public:

virtual void print() {

cerr "попытка поместить значение " _value

" в полный стек\n";

}

// ...

};

Функцию print() теперь можно использовать в catch-обработчике следующим образом:

int main() {

try {

// iStack::push() возбуждает исключение pushOnFull

} catch ( Excp eObj ) {

eObj.print(); // хотим вызвать виртуальную функцию,

// но вызывается экземпляр из базового класса

}

}

Хотя возбужденное исключение имеет тип pushOnFull, а функция print() виртуальна, инструкция eObj.print() печатает такую строку:

Произошло исключение

Вызываемая print() является членом базового класса Excp, а не замещает ее в производном. Но почему?

Вспомните, что объявление исключения в catch-обработчике ведет себя почти так же, так объявление параметра. Когда управление попадает в catch-обработчик, то, поскольку в нем объявлен объект, а не ссылка, eObj инициализируется копией подобъекта Excp базового класса объекта исключения. Поэтому eObj – это объект типа Excp, а не pushOnFull. Чтобы вызвать виртуальные функции из производных классов, в объявлении исключения должен быть указатель или ссылка:

int main() {

try {

// iStack::push() возбуждает исключение pushOnFull

} catch ( const Excp &eObj ) {

eObj.print(); // вызывается виртуальная функция

// pushOnFull::print()

}

}

Объявление исключения в этом примере тоже относится к базовому классу Excp, но так как eObj – ссылка и при этом именует объект-исключение типа pushOnFull, то для нее можно вызывать виртуальные функции, определенные в классе pushOnFull. Когда catch-обработчик обращается к виртуальной функции print(), вызывается функция из производного класса, и программа печатает следующую строку:

попытка поместить значение 879 в полный стек

Таким образом, ссылка в объявлении исключения позволяет вызывать виртуальные функции, ассоциированные с классом объекта-исключения.

<p>19.2.5. Раскрутка стека и вызов деструкторов</p>

Когда возбуждается исключение, поиск его catch-обработчика – раскрутка стека – начинается с функции, возбудившей исключение, и продолжается вверх по цепочке вложенных вызовов (см. раздел 11.3).

Во время раскрутки поочередно происходят аномальные выходы из просмотренных функций. Если функция захватила некоторый ресурс (например, открыла файл или выделила из хипа память), он в таком случае не освобождается.

Существует прием, позволяющий решить эту проблему. Всякий раз, когда во время поиска обработчика происходит выход из составной инструкции или блока, где определен некоторый локальный объект, для этого объекта автоматически вызывается деструктор. (Локальные объекты рассматривались в разделе 8.1.)

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

class PTR {

public:

PTR() { ptr = new int[ chunk ]; }

~PTR { delete[] ptr; }

private:

int *ptr;

};

Локальный объект такого типа создается в функции manip() перед вызовом mathFunc():

void manip( int parm ) {

PTR localPtr;

// ...

mathFunc( parm ); // возбуждает исключение divideByZero

// ...

}

Если mathFunc() возбуждает исключение типа divideByZero, то начинается раскрутка стека. В процессе поиска подходящего catch-обработчика проверяется и функция manip(). Поскольку вызов mathFunc() не заключен в try-блок, то manip() нужного обработчика не содержит. Поэтому стек раскручивается дальше по цепочке вызовов. Но перед выходом из manip() с необработанным исключением процесс раскрутки уничтожает все объекты типа классов, которые локальны в ней и были созданы до вызова mathFunc(). Таким образом, локальный объект localPtr уничтожается до того, как поиск пойдет дальше, а следовательно, память, на которую он указывает, будет освобождена и утечки не произойдет.

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

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

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

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

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

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

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

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

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