LINUX.ORG.RU

История изменений

Исправление emulek, (текущая версия) :

В общем, эти интерфейсы не имеют ничего общего. Интересно, как ты эту проблему решил?

с такой постановкой вопроса поможет двойная диспетчеризация.

На пальцах:

1. два класса Number и Vector наследуются от общего предка Base (он может быть абстрактным, что-бы его никто не мог использовать непосредственно. Впрочем, его можно использовать и не как абстрактный, для реализации NULL/NaN/Empty).

2. оба класса имеют реализацию do_operator(const Base& y) (функция-селектор), которая нужна для вычисления this->value ¤ y.value, однако в классе Number этот this является Number, а в другом классе Vector. Таким образом, тип this в методе do_operator() известен.

3. обе эти функции используют (каждая свой) обратный метод, например do_operator_number(const Number& x), вот так:

void Number::do_operator(const Base& y)
{
  y.do_operator_number(*this);
}
При этом тип *this уже известен (Number), но не известен тип второго операнда y. Функция do_operator_number тоже виртуальная, в двух вариантах, в зависимости от типа второго операнда y.

Таким образом вызывается одна из четырёх функций, если у нас два типа.

Если у нас пять типов, то функций будет 25, и ещё 5 функций-селекторов. Но скорость работы от этого НЕ изменится.

ЗЫЖ в данном конкретном случае для двух типов, я не думаю, что двойная диспетчеризация оправдана. Потому и предложил всего лишь два класса, с наследованием Vector от Number. В реализации все числа будут Vector, и Number::do_operator будет выполняться тогда, и только тогда, когда оба операнда — Number. Т.е. Vector будет обёрткой класса Number.

Исходная версия emulek, :

В общем, эти интерфейсы не имеют ничего общего. Интересно, как ты эту проблему решил?

с такой постановкой вопроса поможет двойная диспетчеризация.

На пальцах:

1. два класса Number и Vector наследуются от общего предка NIL (он может быть абстрактным, что-бы его никто не мог использовать непосредственно. Впрочем, его можно использовать и не как абстрактный, для реализации NULL/NaN/Empty).

2. оба класса имеют реализацию do_operator(const Base& y) (функция-селектор), которая нужна для вычисления this->value ¤ y.value, однако в классе Number этот this является Number, а в другом классе Vector. Таким образом, тип this в методе do_operator() известен.

3. обе эти функции используют (каждая свой) обратный метод, например do_operator_number(const Number& x), вот так:

void Number::do_operator(const Base& y)
{
  y.do_operator_number(*this);
}
При этом тип *this уже известен (Number), но не известен тип второго операнда y. Функция do_operator_number тоже виртуальная, в двух вариантах, в зависимости от типа второго операнда y.

Таким образом вызывается одна из четырёх функций, если у нас два типа.

Если у нас пять типов, то функций будет 25, и ещё 5 функций-селекторов. Но скорость работы от этого НЕ изменится.

ЗЫЖ в данном конкретном случае для двух типов, я не думаю, что двойная диспетчеризация оправдана. Потому и предложил всего лишь два класса, с наследованием Vector от Number. В реализации все числа будут Vector, и Number::do_operator будет выполняться тогда, и только тогда, когда оба операнда — Number. Т.е. Vector будет обёрткой класса Number.