Функция, которая должна иметь общий интерфейс, но должна вести себя по-разному в зависимости от переданных подклассов (не зная, что они есть!) - C ++ - PullRequest
1 голос
/ 15 октября 2019

Я пишу на C ++.

У меня есть разные классы, наследующие от базового класса (скажем, A, B, C, D, все наследующие от Z).

Я хочу написатьфункция, которая принимает 2 объекта типа (супертипа) Z и выполняет некоторую операцию. (Например, у меня может быть f(a, b) или f(c,d), где a, b, c, d относятся к типам A, B, C, D соответственно).

Мне нужен интерфейс (функции) быть общим (нет f_AB(a,b) и f_CD(c,d)).

Однако реализации могут (и могут) отличаться в зависимости от принимаемых классов. (Например, у меня есть f_AB, который делаетчто-то специфичное для AB, f_CD, которое делает что-то специфичное для CD, а также f_AC, f_BC и т. д.)

Подклассы имеют совершенно разные данные, и конкретные операции полностью различаются в зависимости от классовчто я сравниваю.

Когда я использую эту функцию, я не знаю конкретных подклассов 2 аргументов. Предположим, что я делаю что-то вроде

for p in Z {
  for q in Z
    f(p, q) # p and q could be of any subclass of Z! and f must behave accordingly!
}

Каков наилучший способ решения этой проблемы в C ++? Я не могу объединить полиморфизм, виртуальные методы, перегрузку и динамическое приведение, чтобы полностью решить проблему.

Если это не решаемо, возможно ли решить его, отказавшись от некоторых предположений? (Подобно использованию наследования, которое действительно просто необходимо для того, чтобы иметь общие ссылки для зацикливания моих объектов)

1 Ответ

0 голосов
/ 16 октября 2019

Это должно сделать:

class A;

class B;

class C;

class D;

class ZVisitor;


class Z
{
public:
    virtual void Accept (ZVisitor *zv) = 0;

    virtual void f(A* a) = 0;

    virtual void f(B* b) = 0;

    virtual void f(C* c) = 0;

    virtual void f(D* c) = 0;
};

class A : public Z
{
public:

    void Accept(ZVisitor *zv)
    {
        zv->Handle(this);
    }

    void f(A* a);

    void f(B* b);

    void f(C* c);

    void f(D* c);
};

class B : public Z
{
public:
    void Accept(ZVisitor *zv)
    {
        zv->Handle(this);
    }

    void f(A* a);

    void f(B* b);

    void f(C* c);

    void f(D* c);
};

class C : public Z
{
public:

    void Accept(ZVisitor *zv)
    {
        zv->Handle(this);
    }


    void f(A* a);

    void f(B* b);

    void f(C* c);

    void f(D* c);
};

class D : public Z
{
public:
    void Accept(ZVisitor *zv)
    {
        zv->Handle(this);
    }

    void f(A* a);

    void f(B* b);

    void f(C* c);

    void f(D* c);
};

class ZVisitor
{
private:
    Z *z;

public:

    ZVisitor(Z *z)
    {
        this->z = z;
    }

    void Handle(A* a)
    {
        z->f(a);
    }

    void Handle(B* b)
    {
        z->f(b);
    }

    void Handle(C* c)
    {
        z->f(c);
    }

    void Handle(D* d)
    {
        z->f(d);
    }

};

void f(Z *z1, Z *z2)
{
    ZVisitor zvisitor(z2);

    z1->Accept(&zvisitor);
}
...