// cout ‹‹ "co+ci" ‹‹ endl; Это могла быть реализация
_ci.hit(*this);
}
void CTitanic::hit(CTitanic& _ct) {
cout ‹‹ "co+co" ‹‹ endl;
}
// проверим по быстрому, как работает
int main {
CIceberg i1;
CTitanic t1;
CIceberg i2;
CTitanic t2;
i1.hit(t1);
i1.hit(i2);
t1.hit(i1);
t1.hit(t2);
return 0;
}
Пояснения
по коду: взаимодействующие классы надобно определить от одного общего предка, коли они уж плавают и могут друг об друга биться, так и запишем - все варианты взаимодействия должны быть чистыми виртуальными функциями.
В общем, количество действительных реализаций функций уменьшается как раз на количество совпадающих. Не так уж и плохо.
Есть еще способы уменьшить их количество, основанные на преобразованиях классов - неявных или через конструкторы. Я правда не знаю, что раньше может запутать - количество диспетчерских функций или неявные преобразования; тут, пожалуй, можно только порадоваться появлению в стандарте ограничивающего модификатора explicit, который подавляет неявные вызовы конструкторов.
Увы, двойная диспетчеризация в C++ всегда громоздкая и неудобная вещь, и вряд ли будет другой. Если мы добавляем новые классы в диспетчеризацию, приходится переписывать ранее написанные классы; все классы имеют доступ к функциям друг друга или функции должны быть открытыми.
Это - плата за отсутствие в C++ функций, виртуальных по отношению к 2 и более классам.
Шаг 15 - Как сделать массив из чего угодно.
Массивы и оператор operator[].
Давайте попробуем придумать класс, объекты которого вели бы себя как массивы? Поехали. Решим, что класс внутри себя должен иметь для простоты массив, ну там счетчик элементов… вроде больше нечему там быть. Ну раз так, то возьмем стек из Шага 13, для чистоты эксперимента выкинем спорные перегрузки operator+, operator+= и operator-, а для доступа к элементу пишем функцию int getat (int). Но что получается? Значит, добавление-изъятие мы пишем как функции только ради чистоты стиля, а других мотивов нет? А с доступом к элементу нам вообще ничего не мешает - пусть вместо getat будет operator[], а возвращает ссылку - ссылке же можно присвоить значение, а значит, работать будет в обе стороны, и на чтение и на запись!
class CArray {
private:
int a[100];
int iTop;
public:
// Тут смотреть нечего, конструкторы да присваивания, банально