Шаблон архитектуры: функция для обработки двух идентичных реализаций - PullRequest
0 голосов
/ 05 мая 2020
• 1000 получить некоторые результаты от пар (f (A, A), f (B, B), f (C, C)) и так далее. Другими словами, я хочу связать I с express, чтобы две идентичные реализации могли быть объединены для получения одних результатов, а другие - нет (вы не можете получить какой-либо действительный результат от f (A, B)).

Прямо сейчас у меня есть следующее:

#include <iostream>

using namespace std;
class A;
class B;
class I{
public:
  virtual int f (const I &other) const = 0;
  virtual int fSpecific (const A &other) const { throw runtime_error(""); };
  virtual int fSpecific (const B &other) const { throw runtime_error(""); };
};

class A: public I{

public:
 A(int a) : a(a) {} 
 int f (const I &other) const override { other.fSpecific(*this); }
 int fSpecific (const A &other) const override { /*logic here*/ return a + other.a; }
 int a;
};

class B: public I{

public:
 B(int b1, int b2) : b1(b1), b2(b2) {}
 int f (const I &other) const override { other.fSpecific(*this); }
 int fSpecific (const B &other) const override { /*logic here*/ return b1*b1 + b2*b2 + other.b1*other.b1 + other.b2*other.b2; }
private:
 int b1;
 int b2;
};

int f(const I &a, const I &b) {
    a.f(b);
}

int main()
{
    cout << f(A(1), A(2)) << std::endl; // prints 3
    cout << f(B(1, 2), B(3, 4)) << std::endl; // prints 30
    cout << f(A(1), B(3, 4)) << std::endl; // throws an error

    return 0;
}
/*and so on*/

Но я полагаю, что использую неправильную архитектуру. поскольку добавление классов приводит к изменению I. Есть ли лучшее решение для express такого отношения?

Ответы [ 2 ]

0 голосов
/ 05 мая 2020

Ваш интерфейс действительно странный, он запрашивает метод, который не должен быть реализован.

У нас нет нескольких динамических c отправок, кроме std::visit из std::variant.

Таким образом, может помочь следующее:

using V = std::variant<A, B, C>;

int f(const V& v1, const V& v2) {
    struct {
        template <typename T1, typename T2>
        int operator()(const T& t1, const T2& t2) const { throw runtime_error(""); };

        int operator()(const A& a1, const A& a2) const { return a1.a + a2.a; };
        int operator()(const B& b1, const B& b2) const { return b1.b1*b1.b1 + b1.b2*b1.b2 + b2.b1*b2.b1 + b2.b2*b2.b2; };
        int operator()(const C& c1, const C& c2) const { return c1.c * c2.c; };
    } visitor;
    return std::visit(visitor, v1, v2);
}

или сохранение вашей иерархии:

using CV = std::variant<const A*, const B*, const C*>;
class I
{
public:
    virtual ~I() = default;
    virtual CV asVariant() const = 0;
};

class A: public I{
public:
 A(int a) : a(a) {}
 CV asVariant() const override { return this; }
 friend int f (const A& a1, const A& a2) { /*logic here*/ return a1.a + a2.a; }
 int a;
};

class B: public I{
public:
B(int b1, int b2) : b1(b1), b2(b2) {}
 CV asVariant() const override { return this; }
 friend int f (const B& b1, const B& b2) {
    /*logic here*/ return b1.b1*b1.b1 + b1.b2*b1.b2 + b2.b1*b2.b1 + b2.b2*b2.b2;
  }
private:
 int b1;
 int b2;
};


int f(const I& i1, const I& &2) {
    struct {
        template <typename T1, typename T2>
        int operator()(const T1*, const T2*) const { throw runtime_error(""); };

        template <typename T>
        int operator()(const T* t1, const T* t2) const { return f(*t1, *t2); };
    } visitor;
    return std::visit(visitor, i1.AsVariant(), i2.AsVariant());
}

0 голосов
/ 05 мая 2020

Вы можете использовать dynamic_cast:

class I {
public:
    template<typename T>
    void fSpecific (T &other) {
        if (dynamic_cast<T*>(this))
            std::cout << "OK" << std::endl;
        else
            std::cout << "ERROR" << std::endl;
    }
    virtual ~I() {}
};

class A : public I { 
};

class B : public I { 
};

int main()
{
    A a;
    a.fSpecific(a);
    B b;
    b.fSpecific(a);
    b.fSpecific((I&)a);

    return 0;
}

Однако есть некоторые проблемы:

  • Множественное наследование
  • Объекты должны быть динамически преобразованными (что поэтому я добавил виртуальный интерфейс)
  • Приведение в I тоже работает.
...