Link и LinkedList с ключевым словом public. Узлы дерева Tree содержат указатели на
потомков, а также целочисленные значения.
Теперь необходимо справиться с проблемой неоднозначности. Прежде всего имеется
двусмысленность в имени add (добавить), которая отражает двойственность
приписываемого ему значения. Для дерева есть два смысла операции «добавить»:
присоединить узел-потомок и породить узел-подветвь. Первое обеспечивается функцией
add класса LinkedList, второе — функцией add класса Link. После некоторого
размышления программист решает оставить функцию add в смысле «добавить узел-
потомок», но одновременно вводит две новые функции, имена которых отражают цель
операции (добавить подветвь и добавить потомка).
Заметьте, что все три функции по существу — просто переименованные старые. Они не
добавляют нового функционирования, а просто передают управление ранее определенным
функциям. Некоторые объектно-ориентированные языки (например, Eiffel) позволяют
пользователю вводить подобное переименование без создания новой функции.
Двусмысленность в методе onEachDo является более сложной. Здесь правильное действие
состоит в выполнении сквозного прохода по всем узлам дерева. Процесс начинается с
просмотра узлов-потомков, затем возвращается в исходный узел, а затем переходит к
подветвям (которые, естественно, осуществляют рекурсивный проход уже по своим
потомкам). То есть действие является комбинацией методов базовых классов Link и
LinkedList, как это показано в листинге 13.4.
Переименование время от времени оказывается необходимым из-за пересечения понятий
наследования и параметрической перегрузки. Когда в C++ используется перегруженное
имя, то сперва вызывается механизм наследования для поиска контекста, в котором
определена функция. Затем типы параметров анализируются для снятия двусмысленности
в пределах данного контекста. Предположим, что есть два класса A и B, для каждого из
которых определен метод display, но у методов разные аргументы (листинг 13.4).
Пользователь считает, что так как эти два метода различаются по списку параметров,
дочерний класс может наследовать от двух родителей и иметь доступ к обоим методам. К
сожалению, здесь наследования недостаточно. Когда пользователь вызывает метод display
с целочисленным аргументом, компилятор не может принять решение, использовать ли
функцию из класса A (которая соответствует типу аргумента) или же из класса B (которая
встречается первой при заложенном в C++ алгоритме поиска; для ее вызова аргумент
будет приведен от типа integer к типу double). К счастью, компилятор всегда
предупреждает о подобных случаях. Однако предупреждение выдается в точке вызова
метода, а не при описании класса.
Выход в том, чтобы переопределить оба метода для дочернего класса C, как это показано
в листинге 13.4. Мы избежим конкуренции между наследованием и перегрузкой — в
обоих случаях поиск кончается в классе C, где для компилятора уже ясно, что
параметрическая перегрузка используется намеренно.
Листинг 13.4. Взаимодействие наследования и перегрузки
class A
{
public:
void virtual display(int i)
{
printf("in A %d\n", i);
PDF created with pdfFactory Pro trial version www.pdffactory.com