Что делать, если мы хотим обрабатывать коллекцию объектов класса Circle
Shape, т.е. если действительно хотим, чтобы функция better() (представляющая собой вариант нашей старой знакомой функции draw_all(); см. разделы 19.3.2 и 22.1.3) реализовала полиморфизм? По существу, мы не можем этого сделать. В разделах 19.3.3 и 25.4.2 показано, что система типов имеет веские основания отказаться воспринимать тип vector как vector. По той же причине она отказывается принимать тип Array_ref как Array_ref. Если вы не помните, почему, то перечитайте раздел 19.3.3, поскольку данный момент очень важен, даже если это кажется неудобным. a[i].draw()
better() противоречит этому требованию. Когда мы видим в этом выражении точку, а не стрелку (–>), следует ожидать проблем с полиморфизмомЧто нам делать? Во-первых, мы должны работать с указателями (или ссылками), а не с самими объектами, поэтому следует попытаться использовать классы Array_ref
Array_ref и тому подобные, а не Array_ref, Array_ref и т.п.Однако мы по-прежнему не можем конвертировать класс Array_ref
Array_ref, поскольку нам потом может потребоваться поместить в контейнер Array_ref элементы, которые не имеют типа Circle*. Правда, существует одна лазейка.• Мы не хотим модифицировать наш объект класса Array_ref
Shape! Это интересный и совершенно особый случай: наш аргумент против преобразования типа Array_ref в Array_ref не относится к ситуациям, в которых мы не хотим модифицировать класс Array_ref.• Все массивы указателей имеют одну и ту же схему (независимо от объектов, на которые они ссылаются), поэтому нас не должна волновать проблема, упомянутая в разделе 25.4.2.
Array_ref
Array_ref. Итак, нам достаточно просто найти способ это сделать. Рассмотрим примерНет никаких логических препятствий интерпретировать данный массив указателей типа Circle*
Shape* (из контейнера Array_ref). better()
void better2(const Array_ref
{
for (int i = 0; i
if (a[i])
a[i]–>draw();
}
Теперь мы работаем с указателями, поэтому должны предусмотреть проверку нулевого показателя. Для того чтобы гарантировать, что функция better2()
Array_ref, мы добавили несколько квалификаторов const. Первый квалификатор const гарантирует, что мы не применим к объекту класса Array_ref модифицирующие операции, такие как assign() и reset(). Второй квалификатор const размещен после звездочки (*). Это значит, что мы хотим иметь константный указатель (а не указатель на константы); иначе говоря, мы не хотим модифицировать указатели на элементы, даже если у нас есть операции, позволяющие это сделать.Далее, мы должны устранить главную проблему: как выразить идею, что объект класса Array_ref
• в нечто подобное объекту класса Array_ref
better2());• но только если объект класса Array_ref
Это можно сделать, добавив в класс Array_ref
template
class Array_ref {
public:
// как прежде
template
operator const Array_ref
{
// проверка неявного преобразования элементов:
static_cast(*static_cast
// приведение класса Array_ref:
return Array_ref(p),sz);
}
// как прежде
};
Это похоже на головоломку, но все же перечислим ее основные моменты.