Операторы преобразования и оператор ->
Осталось добавить еще пару штрихов. Во-первых, оператор [] в правой части операции присваивания работает уже не так, как было написано, поскольку он возвращает ArrayCursor, а не Foo* или Foo*&. Но причин для беспокойства нет, потому что Foo*() в случае необходимости автоматически преобразует ArrayCursor к Foo*. Вторая проблема заключается в том, что оператор [] не может использоваться слева от оператора ->; на помощь приходит operator->()!
class ArrayCursor {
friend class SparseArray;
private:
SparseArray& array;
Index index;
SparseArray::Node* node;
ArrayCursor(SparseArray& arr, Index i)
: array(arr), index(i), node(NULL) {}
ArrayCursor(SparseArray& arr, SparseArray::Node* n)
: array(arr), node(n), index(n->index) {}
public:
ArrayCursor& operator=(Foo* foo);
operator Foo*() { return node != NULL ? node->content : NULL; };
Foo* operator->()
{
if (node = NULL)
// Инициировать исключение
else
return node->contents;
}
};
Foo* foo = array[Index(17, 29)]; // Работает
array[Index(17, 29)]->MemberOfFoo(); // Тоже работает
Ну вот, теперь можно расслабиться. Для клиентского объекта наш массив ничем не отличается от обычного. Это означает, что вы можете программировать для простой семантики массива и отдельно выбрать внутреннюю реализацию структур данных даже на поздней стадии проекта.