Для на чала надо выяснить один принципиальный вопрос из-за которого возможна полная лажа в дискуссии, так вот собственно сам вопрос в твоем примере
#include <iostream.h>
class CErrors{
public:
virtual void PrintError()=0;
};
class COutMemory: public CError{
public:
virtual void PrintError() {cout<<"COutMemory";}
}
class COutRange: public CError{
public:
virtual void PrintError() {cout<<"COutRange";}
};
void Func(){
throw COutRange();
}
int main(){
try{
Func();
}
catch(CError& error){
error.PrintError();
}
return 0;
}
НЕТ сласса CError!!! если это просто опечатка и CErrors = CError то продолжаем разговор...
ты писал
Класс COutOfMemory является производным от CError. Я не знаком с термином "срезание объекта", но судя по всему ты имеешь ввиду процедуру приведения типа указателя производного класса к типу указателя на бозовый класс. Благодаря этому через этот указатель будет виден только фрагмент базового класса, а фрагмент производного класса окажется невиден. Т.е вот так:
static_cast <CError*> (COutOfMemory*);
Если я правильно тебя понял это и обозначает термин "срезание"...
Нет ты понял не правильно, срезание объекта это следующее (кстати при использовании указателей или ссылок срезания полиморфных объектов НЕ происходит, оно и понятно веть имея поинтер на базовый класс и вызывая виртуальную функцию... вызовется функция того объекта который реально был создан, т.е. если был создан объект производного класс то и вызовется функция производного класса (еще раз обращу внимание это при условии что поинтер то был на БАЗОВЫЙ) - это просто описание работы виртуальных функций), продолжим про срезание... так вот .. этот код
throw COutOfMemory();
...
catch(CErrors error)
{
error.ShowError();
}
эквивалентен следующему В ПЛАНЕ СРЕЗАНИЯ (а не времени жизни объектов)
COutOfMemory outOfMemory();
CError error(outOfMemory); // вот здесь и происходит срезание т.к. объект error
// имеет тип CError и ничего об COutOfMemory не знает в том числе
// и то что функция ShowError() объеска error никакого сообщения
//НЕ выдает, отсюда и термин срезание... т.е. мы срезали объект
// с типом COutOfMemory (и функционалом объекта типа COutOfMemory),
// до типа CError (и соответственно функционалом объекта типа CError)
...
catch(CErrors & error) // здесь ссылка для того чтобы не создавать ЕЩЕ один
// временнный объект
{
error.ShowError();
}
идем дальше
throw COutOfMemory();
...
catch(CErrors error)
{
error.ShowError();
}
Тут не много другая история...
Сначала создаётся объект-исключение ( throw COutOfMemory(); ). Т.к в блоке catch объявлена не ссылка и не указатель, а именно переменна с типом класс, то происходит создание ещё одного объекта, но на этот раз базового класса. Таким образом в стеке уже два объекта.
Абсолютно верно, я же именно это и написал вот смотри
если рассмотреть второй вариант
throw COutOfMemory();
...
catch(CErrors error)
{
error.ShowError();
}
то тут сначала создается на стеке объект типа COutOfMemory (вот туточки создается throw COutOfMemory(); ) ......
и далее
.......
тогда в catch происходит создание стекового объекта типа CErrors (с вызовом копирующего конструктора)
.......
Это
Далее происходит срезание объекта производного класса (того которым бросались тут - throw COutOfMemory(); ) и копирование его при помощи конструктора копирования в объект который был создан тут catch(CErrors error) ... Область видимости этого объекта - блок catch(...) - это ясно. Т.е когда будет выполнен выход из блока catch(...) то этот экземпляр будет автоматически разрушен вызовом его деструктора
тоже верно я и об этом написал смотри мой предыдущий ответ, а теперь по поводу этого
а какая область видимости будет у объекта созданного throw COutOfMemory(); ? - сколько он будет висеть в стеке? Предполагаю, что до тех пор, пок не будет выполнено завершение подпрограммы которя бросала исключение.
тоже не верная догадка, вот смотри это
throw COutOfMemory();
эквивалентно (в плане жизни объектка) следующему
printf(std::string("bubu").c_str());
спрашивается как же долго будет жить стековый объект типа std::string, а ответ такой, ооочень не долго и по выполнению функции printf он уничтожится, то же самое и утебя после обработки исключения т.е. вот этого
{
error.ShowError();
}
т.е. после выполнения этого блока сначала уничножится объект типа CError, а потом сразу за ним уничножится объект типа COutOfMemory,кстати я и об этом писал вот
...
затем опять после вызова error.ShowError(); после закрытия } удаляется САМ временный (стековый) объект типа CErrors, а потом опять же САМ удаляется стековый объест типа COutOfMemory
...
по поводу этого
И последнее:
ну и наконец третий вариант
throw new COutOfMemory();
...
catch(CErrors * error)
{
error->ShowError();
delete error;
}
тут у нас для начала создаетя в КУЧЕ!!!! объект типа COutOfMemory, далее мы бросаемся этим самым объектом потом ловим его и тут уже естественно надо его замочить потому как память отожрана.
Я думаю, что в этом случае, вместо
бросаемся этим самым объектом
правильно будет говорить:
"бросаемся указателем на этот самый объект"
могу сказать следующее, что не знаю как правильно сказать (объект или указатель) но смысл был именно в этом