19.2.4. Объекты-исключения и виртуальные функции
19.2.4. Объекты-исключения и виртуальные функции
Если сгенерированный объект-исключение имеет тип производного класса, а обрабатывается catch-обработчиком для базового, то этот обработчик не может использовать особенности производного класса. Например, к функции-члену value(), которая объявлена в классе pushOnFull, нельзя обращаться в catch-обработчике Excp:
catch ( const Excp &eObj ) {
// ошибка: в классе Excp нет функции-члена value()
cerr "попытка поместить значение " eObj.value()
" в полный стек ";
}
Но мы можем перепроектировать иерархию классов исключений и определить виртуальные функции, которые можно вызывать из catch-обработчика для базового класса Excp с целью получения доступа к функциям-членам более специализированного производного:
// новые определения классов, включающие виртуальные функции
class Excp {
public:
virtual void print( string msg ) {
cerr "Произошло исключение"
endl;
}
};
class stackExcp : public Excp { };
class pushOnFull : public stackExcp {
public:
virtual void print() {
cerr "попытка поместить значение " _value
" в полный стек ";
}
// ...
};
Функцию 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 в полный стек
Таким образом, ссылка в объявлении исключения позволяет вызывать виртуальные функции, ассоциированные с классом объекта-исключения.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
R.10.2 Виртуальные функции
R.10.2 Виртуальные функции Если класс base содержит виртуальную (§R.7.1.2) функцию vf, а производный от него класс derived также содержит функцию vf того же типа, тогда вызов vf для объекта класса derived является обращением к derived::vf, даже если доступ к этой функции происходит через
39. Виртуальные функции стоит делать неоткрытыми, а открытые — невиртуальными
39. Виртуальные функции стоит делать неоткрытыми, а открытые — невиртуальными РезюмеВ базовых классах с высокой стоимостью изменений (в частности, в библиотеках) лучше делать открытые функции невиртуальными. Виртуальные функции лучше делать закрытыми, или защищенными —
Правило 9: Никогда не вызывайте виртуальные функции в конструкторе или деструкторе
Правило 9: Никогда не вызывайте виртуальные функции в конструкторе или деструкторе Начну с повторения: вы не должны вызывать виртуальные функции во время работы конструкторов или деструкторов, потому что эти вызовы будут делать не то, что вы думаете, и результатами их
8.2. Глобальные объекты и функции
8.2. Глобальные объекты и функции Объявление функции в глобальной области видимости вводит глобальную функцию, а объявление переменной – глобальный объект. Глобальный объект существует на протяжении всего времени выполнения программы. Время жизни глобального
11.3.1. Объекты-исключения
11.3.1. Объекты-исключения Объявлением исключения в catch-обработчикемогут быть объявления типа или объекта. В какихслучаях это следует делать? Тогда, когда необходимополучить значение или как-то манипулировать объектом,созданным в выражении throw. Если классы исключений
12.3. Объекты-функции
12.3. Объекты-функции Наша функция min() дает хороший пример как возможностей, так и ограничений механизма шаблонов:template typename Typeconst Type&min( const Type *p, int size ){Type minval = p[ 0 ];for ( int ix = 1; ix size; ++ix )if ( p[ ix ] minval )minval = p[ ix ];return minval;}Достоинство этого механизма – возможность определить
12.3.1. Предопределенные объекты-функции
12.3.1. Предопределенные объекты-функции Предопределенные объекты-функции подразделяются на арифметические, логические и сравнительные. Каждый объект – это шаблон класса, параметризованный типами операндов. Для использования любого из них необходимо включить
12.3.2. Арифметические объекты-функции
12.3.2. Арифметические объекты-функции Предопределенные арифметические объекты-функции поддерживают операции сложения, вычитания, умножения, деления, взятия остатка и вычисления противоположного по знаку значения. Вызываемый оператор – это экземпляр, ассоциированный с
12.3.3. Сравнительные объекты-функции
12.3.3. Сравнительные объекты-функции Сравнительные объекты-функции поддерживают операции равенства, неравенства, больше, больше или равно, меньше, меньше или равно.equal_tostring stringEqual;sres = stringEqual( sval1, sval2 );ires = count_if( svec.begin(), svec.end(),Равенство:equal_toType* equal_tostring(), sval1 );not_equal_tocomplex
12.3.4. Логические объекты-функции
12.3.4. Логические объекты-функции Логические объекты-функции поддерживают операции "логическое И" (возвращает true, если оба операнда равны true, – применяет оператор &&, аcсоциированный с типом Type), "логическое ИЛИ" (возвращает true, если хотя бы один из операндов равен true, –
17.5. Виртуальные функции в базовом и производном классах
17.5. Виртуальные функции в базовом и производном классах По умолчанию функции-члены класса не являются виртуальными. В подобных случаях при обращении вызывается функция, определенная в статическом типе объекта класса (или указателя, или ссылки на объект), для которого она
17.5.4. Виртуальные функции и аргументы по умолчанию
17.5.4. Виртуальные функции и аргументы по умолчанию Рассмотрим следующую простую иерархию классов:#include iostreamclass base {public:virtual int foo( int ival = 1024 ) {cout " base::foo() -- ival: " ival endl;return ival;}// ...};class derived : public base {public:virtual int foo( int ival = 2048 ) {cout " derived::foo() -- ival: " ival endl;return ival;}// ...};Проектировщик
17.5.8. Виртуальные функции, конструкторы и деструкторы
17.5.8. Виртуальные функции, конструкторы и деструкторы Как мы видели в разделе 17.4, для объекта производного класса сначала вызывается конструктор базового, а затем производного класса. Например, при таком определении объекта NameQueryNameQuery poet( "Orlen" );сначала будет вызван
1.18 Виртуальные Функции
1.18 Виртуальные Функции Предположим, что мы пишем программу для изображения фигур на экране. Общие атрибуты фигуры представлены классом shape, а специальные атрибуты – специальными классами:class shape (* point center; color col; //... public: void move(point to) (* center=to; draw(); *) point where() (* return center; *) virtual void
7.2.8 Виртуальные Функции
7.2.8 Виртуальные Функции Виртуальные функции преодолевают сложности решения с пмощью полей типа, позволяя программисту описывать в базовом классе функции, которые можно переопределять в любом проиводном классе. Компилятор и загрузчик обеспечивают правильное
8.5.4 Виртуальные Функции
8.5.4 Виртуальные Функции Если базовый класс base содержит virtual (виртуальную) (#8.1) функцию vf, а производный класс derived также содержит функцию vf, то обе функции должны иметь один и тот же тип, и вызов vf для объекта класса derived вызывает derived::vf. Например:struct base (* virtual void vf (); void f (); *);class