178
С представителями
можно делать все то же самое, что и с объектами класса. При этом необходимо
учитывать следующее:
•
Для представителей не нужно создавать отдельный класс
Class
.
•
С представителями не приходится объявлять друзей (обычно объект класса должен быть
другом того класса, который он представляет).
•
Настоящие объекты классов заметно упрощают моделирование иерархий классов.
•
Настоящие объекты классов упрощают создание гомоморфного
интерфейса для описанных
выше сведений о классах.
•
С объектами классов отличия между тем, что относится к объектам класса/представителям, и
тем, что относится к реальным экземплярам, становятся более отчетливыми.
В общем и целом, объекты классов оказываются более гибкими при
незначительно усложнении
реализации по сравнению с экземплярами.
Невидимые
указатели
Нетривиальное использование С++ напоминает один известный эпизод из фильма «Сумеречная зона».
Героиня попадает в автомобильную аварию. Она безуспешно ждет, пока кто-нибудь проедет по дороге,
и в конце концов решает отправиться за помощью. Но куда бы она ни шла, как бы внимательно ни
следила за направлением, она всегда возвращалась к обломкам машины. Так и с указателями: куда бы
вы ни шли, вы все равно вернетесь к обломкам. Хм… пожалуй, мне
следовало подыскать более
оптимистичное сравнение.
В этой главе мы снова возвращаемся к теме указателей, на этот раз — в свете гомоморфных иерархий
классов. Рассматриваемые здесь указатели я называю
невидимыми (invisible pointers), поскольку в
большинстве
случаев можно устроить так, чтобы клиент абсолютно ничего не знал о присутствии
указателя между ним и целевым объектом. Джеймс Коплин (James Coplien) рассматривает частный
случай невидимых указателей и называет его «парадигма конверт/письмо»; мы же поговорим о более
общем случае.
Основные концепции
Если гомоморфизм хорошо
подходит для других классов, значит, он подойдет и для указателей.
Концепция проста: указатель и указываемый объект порождаются от одного и того же чисто
абстрактного базового класса.
class Foo {
public:
virtual void do_something() = 0;
virtual void do_something_else() = 0;
};
class PFoo : public Foo {
private:
Foo*
foo;
public:
virtual void do_something() { foo->do_something(); }
virtual void do_something_else() { foo->do_something_else(); }
};
class Bar : public Foo {
// Все для производного класса
};
Вместо перегрузки оператора
->
в
PFoo
используется делегирование.
Приведенный фрагмент лишь
слегка затрагивает данную тему. На практике приходится учитывать множество деталей, начиная с
того, как скрыть указатели и указываемые объекты от клиентов.
Do'stlaringiz bilan baham: