Контравариантность по абстрактным классам

Я хотел бы создать красивый интерфейс на C ++, в котором каждая реализация должна иметь определенное добавление для себя.

Я хотел бы сделать что-то вроде этого:

    class A{
...
virtual A& operator+(const A& other) =0;
...
}
// this is my interface or abstract class.class B : A{
...
B& operator+(const B& other);
...
}
// this is the kind of implementation i would like. a B element can be added by another B element only ! At least this the constraint I am aiming at.

так как с ++ не принимает контравариантность, моя функция B& operator+(const B& other) не реализует virtual A& operator+(const A& other), Есть ли какой-нибудь хитрый (но немного чистый …) способ сделать это?

6

Решение

template<class Y>
class A
{
virtual Y& operator+=(const Y& other) = 0;
};

class B : A<B>
{
// must implement B& operator+=(const B& other) else B is abstract
};

это один из способов. Эта идиома распространена при реализации политики. Увидеть http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

7

Другие решения

То, что вы пытаетесь сделать, невозможно ни на одном языке, потому что это не имеет смысла.

Это правда, что методы противоречивы в типах аргументов в некоторых языках, но это означает, что метод перегружен, если он принимает супертипом. То есть operator+(const A&) будет перегружен для operator+(const B&), Но не наоборот. Потому что, когда у вас есть два экземпляра (давайте назовем их x а также y) и писать x + yметод будет вызван, и компилятор не может знать, будут ли оба иметь один и тот же подтип, так как эта информация будет доступна только во время выполнения. Так что во время выполнения это единственный раз, когда вы можете проверить это.

Так:

  1. Если вам нужен интерфейс и вы будете использовать его полиморфно, то оператор должен взять интерфейс и проверить во время выполнения, что он получил совместимый экземпляр (но это не внушает доверия дизайну).
  2. Если вам не нужно использовать его полиморфно, не беспокойтесь об определении интерфейса вообще. Просто используйте + в шаблоне, который будет использовать его (он должен быть шаблоном, если он не полиморфный), и компилятор будет суки, когда он не определен. Вы можете написать класс проверки концепции рано обнаруживать и избегать ошибок со слишком глубоким стеком расширения шаблона.
5