Home > Blockchain >  c : cross interactions within dual hierarchy
c : cross interactions within dual hierarchy

Time:05-25

In a C application, I have two class hierarchies, one for Workers and for Stuff. I want each sub-class of Worker to interact differently with each sub-class of Stuff through a do_stuff function. I'm not sure how to do that without systematically down-casting both the worker and stuff inside do_stuff and have specific treatments for each possibility.

Moving do_stuff to be a method for either Worker or Stuff and overriding in the sub-classes removes the need for one down-cast, but not the other.

Is there a specific good pratice to handle similar cases ?

Code structure is as below:

class Worker;
class Worker1 : public Worker;
class Worker2 : public Worker;

class Stuff;
class StuffA : public Stuff;
class StuffB : public Stuff;

void do_stuff(Worker worker, Stuff stuff);

int main() {
    vector<Worker*> worker_vec = whatever;
    vector<Stuff*> stuff_vec = whatever;

    for(Worker* worker : worker_vec) {
        for(Stuff* stuff: stuff_vec) {
            do_stuff(*worker, *stuff);
        }
    }
    return 0;
}

CodePudding user response:

A bit of an effort to implement, but at least possible:

class Worker1;
class Worker2;

class Stuff
{
public:
    virtual ~Stuff() { }
    virtual void doStuff(Worker1*) = 0;
    virtual void doStuff(Worker2*) = 0;
};

class Worker
{
public:
    virtual ~Worker() { }
    virtual void doStuff(Stuff* stuff) = 0;
};
class Worker1 : public Worker
{
    void doStuff(Stuff* stuff) override
    {
        stuff->doStuff(this);
    }
};

// another approach: CRTP; spares the work of having to rewrite
// the overridden function again and again...
template <typename T>
class Stuffer : public Worker
{
public:
    void doStuff(Stuff* stuff) override
    {
        stuff->doStuff(static_cast<T*>(this));
    }
};
class Worker2 : public Stuffer<Worker2>
{
};

class Worker2 : public Worker
{
    void doStuff(Stuff* stuff) override
    {
        stuff->doStuff(this);
    }
};

class StuffA : public Stuff
{
public:
    void doStuff(Worker1*) override
    {
        std::cout << "StuffA   Worker1\n";
    }
    void doStuff(Worker2*) override
    {
        std::cout << "StuffA   Worker2\n";
    }
};
class StuffB : public Stuff
{
public:
    void doStuff(Worker1*) override
    {
        std::cout << "StuffB   Worker1\n";
    }
    void doStuff(Worker2*) override
    {
        std::cout << "StuffB   Worker2\n";
    }
};

int main()
{
    std::vector<Worker*> worker_vec = { new Worker1, new Worker2 };
    std::vector<Stuff*> stuff_vec = { new StuffA, new StuffB };

    for(Worker* worker : worker_vec)
    {
        for(Stuff* stuff: stuff_vec)
        {
            worker->doStuff(stuff);
        }
    }
    return 0;
}

All without explicit (dynamic_)casts...

For Worker2 I did the implementation via the curiously recurring template pattern – re-introducing a cast, yes, but a static_cast which is for free at runtime so probably won't mind. It would relieve you from having to write the overridden function again and again...

Demo on godbolt.

  • Related