Этот класс exception_response является потомко
//...
map
defect_response * Response;
exception_response *Response2;
Response = new defect_response;
Respone2 = new exception_response;
ErrorTable[123] = Response; // Хранит объект типа
// defect_response.
ErrorTable[456] = Response2; // Хранит объект типа
// exception_response.
//...
Это определение означает, что объект типа ErrorTable может связывать с соответствующим но
//...
defect_response *ProblemSolver;
ProblemSovler = ErrorTable[123];
ProblemSolver->doSomething();
ProblemSovler = ErrorTable[456];
ProblemSovler->doSomething();
//...
Несмотря на то что Переменная ProblemSolver представляет собой указатель на объект defect_response, полиморфизм позволяет этой переменной указывать на объект типа exception_response или любой другой объект, выведенный из класса defect_response. Поскольку метод doSomething () объявлен виртуальным в классе defect_response, компилятор может выполнить динамическое связывание. Это дает гарантию корректного вызова метода doSomething() при выполнении приложения. Именно динамическое связывание позволяет каждому потомку класса defect_response определить собственный метод doSomething (). Нам нужно, чтобы вызов метода doSomething() зависел от того, ссылка на какой именно потомок класса defect_response используется при этом. Рассматриваемый метод позволяет связывать номера ошибок с объектами, имеющими отношение к обработке определенных сбойных ситуаций. С помощью этого метода можно значительно упростить код обработки ошибок. В листинге 7.1, например, показано, как значение, возвращаемое некоторой функцией, можно использовать для выбора соответствующего объекта обработки ошибок.
// Листинг 7.1. Использование значений, возвращаемых
// функцией, для определения корректного
// объекта типа ErrorHandler
void importantOperation(void) {
//. . .
Result = reliableOperation(); if(Result != Success){
defect_response *Solver;
Solver = ErrorTable[Result];
Solver->doSomething();
}
else{
// Продолжение обработки.
}
// . . .
}
В листинге 7.1 обратите внимание на то, что мы не используем последовательность if- или case-инструкций. Объект отображения позволяет получить непосредственный доступ к желаемому объекту обработки ошибок по индексу. Конкретный метод doSomething(), вызываемый в листинге 7.1, зависит от значения переменной Result. Безусловно, данный пример демонстрирует упрощенную схему обработки ошибочных ситуаций. Так, например, в листинге 7.1 не показано, кто (или что) отвечает за управление динамически выделяемой памятью для объектов, хранимых в отображении ErrorTable. Кроме того, здесь не учтено, что функции reliableOperation() и doSomething() могут выполниться неудачно. Поэтому реальный код будет, конечно же, несколько сложнее, чем тот, что приведен в листингe 7.1. Но все же этот пример ясно показывает, как одним «ударом» обработать множество ситуаций сбоя. Мы можем пойти еще дальше. В листинге 7.1 предполагается, что все возможные ошибки будут охвачены объектами типа ErrorTable. Все ErrorTable-объекты представляют собой либо объекты типа defect_response, либо объекты, выведенные из класса defect_response. А что, если у нас будет несколько семейств классов обработки ошибок? В листинге 7.2 показано, как с помощью шаблонов сделать функцию importantOperation () более общей.
// Листинг 7.2. Использование шаблона в функции // importantOperation()
template
T ErrorTable; //.. .
U *Solver; //...
Solver = ErrorTable[Result]; Solver->doSomething () ; //...
};