Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы на вопросы Осадчий А.В. гр.010902.docx
Скачиваний:
11
Добавлен:
24.04.2019
Размер:
143.34 Кб
Скачать

47. Конструкторы, деструкторы и обработка исключений. Исключения и наследование.

Когда выброшено исключение, начинается разматывание стека с вызовом необходимых деструкторов. Однако деструкторы в этом случае вызываются только для полностью конструированных локальных объектов. Это означает, что если исключение выброшено в конструкторе объекта, для самого этого объекта деструктор вызван не будет. Будут вызваны только деструкторы его элементов-объектов и базовых классов. Поэтому, если объект содержал уже к этому времени указатели, например, на выделенную динамическую память, она освобождаться не будет. Возникнет утечка памяти.

Как пример:

Исключение в конструкторе

// Construct.срр: Исключение в конструкторе. //

#inciude <stdio.h>

#include <stdlib.h>

#include <string.h>

#pragma hdrstop

#include <condefs.h>

void* operator new[](size_t size)

// Глобальная new[].

{

printf("Global new[].\n");

return malloc(size);

}

void operator delete[](void *p) // Глобальная delete[].

{

printf("Global delete[].\n");

free (p) ;

}

class Hold { // Класс, содержащий динамический массив char. char *ptr;

public:

Hold(char *str) // Конструктор преобразования из char*.

{

printf("Constructor.\n") ;

ptr = new char[strlen(str)+1] ;

strcpy(ptr, str) ;

// printf("Constructor: throwing exception...\n");

// throw "Exception!";

} ~Hold() // Деструктор.

{

printf("Destructor.\n") ;

delete [ ] ptr;

}

void Show() // Распечатка строки.

{

printf("My contents: %s\n", ptr);

} };

int main() {

try {

Hold h = "Some string."; // Попытка конструировать

// объект. h.Show() ;

} catch(char *str) {

printf("Message caught: %s\n", str);

}

printf("Exiting main...\n");

return 0;

}

Программа создает локальный в try-блоке объект класса Hold. Строка в конструкторе, выбрасывающая исключение, пока закомментирована, и программа выводит:

Constructor.

Global new[].

My contents: Some string.

Destructor.

Global delete [].

Exiting main...

Если же раскомментировать строку, будет выброшено исключение, причем, поскольку деструктор не полностью конструированного объекта не вызывается, операция delete [ ] для уже выделенной строки выполнена не будет:

Constructor.

Global new[].

Constructor: throwing exception...

Message caught:Exception!

Exiting main...

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

Хотя деструктор не вызывается, память объекта (не та, на которую он может ссылаться посредством указателей, а его собственная) автоматически удаляется. По сути, то же происходит и с локальными объектами, только там не полностью конструированный объект просто удаляется со стека, здесь же вызывается операция класса delete.

Определенный пользователем класс исключения должен быть определен, как класс расширяющий (наследующий) встроенный класс Exception. Ниже приведены методы и свойства класса Exception, доступные дочерним классам.

Пример : Встроеный класс Exception

<?php

class Exception

{

protected $message = 'Unknown exception'; // сообшение

protected $code = 0; // Код исключения,

определяемый пользователем

protected $file; // файл в котором было

выброшено исключение

protected $line; // строка в которой было

выброшено исключение

function __construct($message = null, $code = 0);

final function getMessage(); // Возвращает сообшение

исключения

final function getCode(); // Код исключения

final function getFile(); // Файл, где выброшено

исключение

final function getLine(); // Строка, выбросившая исключени

final function getTrace(); // Массив backtrace()

final function getTraceAsString(); // Обратная трассировка как

строка

/* Overrideable - т.е. то, что можно переопределить */

function __toString(); // должен вернуть

форматированную строку, для отображения

}

Если класс, наследуемый от Exception переопределяет конструктор, необходимо вызвать в конструкторе parent::__construct(), чтобы быть уверенным, что все данные будут доступны. Метод __toString() может быть переопределен, что бы обеспечить нужный вывод, когда объект преобразуется в строку.