2017-01-01 7 views
2

Прошу прощения, если этот вопрос был задан раньше, я очень старался найти что-то подобное, но я даже не был уверен, что искать.Каков правильный способ определения интерфейса самореференции?

Предположим, что у меня есть следующий интерфейс (это просто пример, мой конкретный случай не имеет ничего общего с операторами или дополнение):

class AddAndSub 
{ 
public: 
    virtual AddAndSub operator +(AddAndSub const &) = 0; 
    virtual AddAndSub operator -(AddAndSub const &) = 0; 
} 

С a + b могут быть выражены как a - (-b) и a - b как a + (-b) (для простоты предположим, что отрицание хорошо определено для всех типов получения), мой первый инстинкт заключался в том, чтобы имитировать это свойство в реализации, поэтому только один из операторов должен быть явно определен:

class AddAndSub 
{ 
public: 
    virtual AddAndSub operator +(AddAndSub const & b) 
    { 
    return *self - (-b); 
    } 
    virtual AddAndSub operator -(AddAndSub const & b) 
    { 
    return *self + (-b); 
    } 
} 

Однако я не полностью удовлетворен своим решением, так как мне по-прежнему требуется определить хотя бы одну из операций, но он явно не применяется кодеком и не позволяет определить один результат в очень нежелательном сообщении об ошибке «Переполнение стека ». Я могу оставить интерфейс так, как он есть в первом примере, чтобы убедиться, что каждый класс, реализующий его, определяет необходимые методы, но по очереди приводит к большому количеству избыточного кода в нетривиальных случаях.

Есть ли способ уменьшить избыточность кода в подобных ситуациях, сохраняя при этом проверку времени компиляции и оставляя выбор того, какие методы реализовать пользователю интерфейса?

PS: Я знаю, что могу просто сделать один из этих методов чистым виртуальным, но тогда я не могу выбрать, какой метод я могу определить в случае, когда сложнее реализовать дополнение, чем вычитание (что TBH - это просто незначительный nitpick, но мне все еще интересно, есть ли лучший способ).

+0

Боковое примечание: проектирование плюс оператор, который работает интуитивно понятным способом для иерархии открытого класса, является трудным. Просто сохранение a + b = b + a является огромной проблемой. Интересный базовый класс для правильного добавления некоторого очень производного класса тоже интересен. –

+1

Я бы не использовал такие операторы в интерфейсе полиморфизма времени исполнения, иначе. виртуальных операторов. Это решительно ограничит гибкость вашего кода. Рассмотрите возможность использования полиморфизма времени компиляции и общего программирования при работе с арифметическими операторами. –

ответ

1

Лучше, чтобы ваш интерфейс был чисто абстрактным. Если вы хотите реализовать operator-() в терминах оператора +() или наоборот, сделайте это в своем классе (-ях) реализации.

Если по какой-то причине вы действительно хотите свести к минимуму количество методов, которым должен переопределить класс (ы) реализации, подумайте о создании вспомогательного класса, который подклассифицирует ваш интерфейс и реализует некоторые методы с точки зрения других. Вы можете пометить эти методы как final (функция C++ 11), чтобы запретить их переопределять ваш класс реализации, который будет подклассифицировать вспомогательный.

+0

Классы помощников кажутся решением моей проблемы, однако я надеялся на что-то более похожее на Haskell 'Eq', где ему нужно только' == 'или'! = 'Работать. –