Чтение онлайн

на главную - закладки

Жанры

Идиомы и стили С++

Makhmutov Albert

Шрифт:

#include ‹iostream.h›

// Форвардные объявления

class CTitanic;

class CIceberg;

class CFloating;

// Абстрактный базовый класс

class CFloating {

public:

 virtual void hit(CIceberg&)=0;

 virtual void hit(CTitanic&)=0;

public:

 virtual void hit(CFloating&)=0;

};

//
Класс айсберга

class CIceberg {

public:

 virtual void hit(CIceberg&);

 virtual void hit(CTitanic&);

public:

 virtual void hit(CFloating&);

};

// Первая диспетчерская функция

void CIceberg::hit(CFloating& _co) {

 _co.hit(*this);

}

// Две реализации взаимодействия

void CIceberg::hit(CIceberg& _ci) {

 cout ‹‹ "ci+ci" ‹‹ endl;

}

void CIceberg::hit(CTitanic& _ct) {

 cout ‹‹ "ci+co" ‹‹ endl;

}

// Класс Титаника

class CTitanic {

public:

 virtual void hit(CIceberg&);

 virtual void hit(CTitanic&);

public:

 virtual void hit(CFloating&);

};

// Еще одна диспетчерская функция

void CTitanic::hit(CFloating& _co) { _co.hit(*this); }

// А вот эта функция могла бы быть реализацией

// но мы ее тоже делаем диспетчерской;

// в этом фрагменте диспетчеризация тройная.

void CTitanic::hit(CIceberg& _ci) {

 // 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:

// Тут смотреть нечего, конструкторы да присваивания, банально

 CArray :iTop(0) {}

 CArray (const CArray& _ca) {

iTop = _ca.iTop;

for (int i=0; i++; i ‹100) a[i]= _ca.a[i];

 }

 CArray& operator=(const CArray& _ca) {

if (this==&_ca) return *this;

for (int i=0; i++; i ‹100) a[i]= _ca.a[i];

iTop = _ca.iTop;

return *this;

 }

 CArray& add (int _i) {a[iTop]=_i; iTop++; return *this;}

 int pop(void) {iTop-; return a[iTop+1];}

 // Две функции доступа к элементам массива

 int& getat (int _i){return a[_i];}

 int& operator[](int _i){return a[_i];}

Поделиться:
Популярные книги

Шаман. Похищенные

Калбазов Константин Георгиевич
1. Шаман
Фантастика:
боевая фантастика
попаданцы
6.44
рейтинг книги
Шаман. Похищенные

Младший сын князя

Ткачев Андрей Сергеевич
1. Аналитик
Фантастика:
фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Младший сын князя

Мама из другого мира. Дела семейные и не только

Рыжая Ехидна
4. Королевский приют имени графа Тадеуса Оберона
Любовные романы:
любовно-фантастические романы
9.34
рейтинг книги
Мама из другого мира. Дела семейные и не только

Имя нам Легион. Том 9

Дорничев Дмитрий
9. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 9

Адвокат Империи 7

Карелин Сергей Витальевич
7. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 7

Тот самый сантехник. Трилогия

Мазур Степан Александрович
Тот самый сантехник
Приключения:
прочие приключения
5.00
рейтинг книги
Тот самый сантехник. Трилогия

Сойка-пересмешница

Коллинз Сьюзен
3. Голодные игры
Фантастика:
социально-философская фантастика
боевая фантастика
9.25
рейтинг книги
Сойка-пересмешница

Идеальный мир для Лекаря 10

Сапфир Олег
10. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 10

Последний из рода Демидовых

Ветров Борис
Фантастика:
детективная фантастика
попаданцы
аниме
5.00
рейтинг книги
Последний из рода Демидовых

Барону наплевать на правила

Ренгач Евгений
7. Закон сильного
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Барону наплевать на правила

Божьи воины. Трилогия

Сапковский Анджей
Сага о Рейневане
Фантастика:
фэнтези
8.50
рейтинг книги
Божьи воины. Трилогия

Вперед в прошлое 5

Ратманов Денис
5. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 5

Локки 4 Потомок бога

Решетов Евгений Валерьевич
4. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Локки 4 Потомок бога

Назад в СССР 5

Дамиров Рафаэль
5. Курсант
Фантастика:
попаданцы
альтернативная история
6.64
рейтинг книги
Назад в СССР 5