In a C application, I have two class hierarchies, one for Worker
s 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.