Reputation: 417
I have devices I need to do operations on. I have one base class BASE
and a child class TYPE1
.
Each device is an instance of TYPE1
. These get instantiated by another class depending on what is present in an xml configuration file.
class BASE {
public:
BASE();
virtual ~BASE();
};
class TYPE1 : public BASE {
public:
TYPE1();
};
Now I store pointers to these instances in an std::unordered_map
defined as:
std::unordered_map <std::string, TYPE1 *> myDevices;
with std::string
being an identification key that is also used in configuration files.
The std::unordered_map
gives me quick direct access to an object if I need it and the convenience to do the same operation on all the devices if I iterate through it using
for ( auto& elem : myDevices ) {
//do stuff
}
The order of the devices is unimportant, hence the std::unordered_map
.
I use that extensively throughout the code.
Now I have the need for a TYPE2
that is also a child of BASE
but nevertheless a different type.
TYPE1
and TYPE2
both have the same methods implemented - they function differently - but yield the same results
My question :
How do I modify
std::unordered_map <std::string, TYPE1 *> myDevices;
so it accepts all types of classes like
std::unordered_map <std::string, acceptAnyTypeOfClass *> myDevices;
I'm blocked with this and while I think I could get around it it would get ugly very quickly and I would really like to do it in a clean way. Is what I'm asking possible and if so how please?
Upvotes: 1
Views: 1981
Reputation: 73376
The first option that comes to mind would be to use a pointer to the base class, because TYPE1
and TYPE2
objects are all BASE
objects:
std::unordered_map <std::string, BASE*> myDevices;
The question is then ho wto make the difference between TYPE1*
pointers and TYPE2*
pointers ?
As TYPE1
and TYPE2
both have the same methods implemented, the best approach would probably be to use polymorphism, using virtual functions:
class BASE {
public:
BASE();
virtual void doSomething()=0;
virtual ~BASE();
};
class TYPE1 : public BASE {
public:
TYPE1();
void doSometing() override { /* the code for TYPE 1 devices*/ }
};
class TYPE2 : public BASE {
public:
TYPE2();
void doSometing() override { /* the code for TYPE 2 devices*/ }
};
You can then invoke the functions without worrying about the true type of the base object:
std::unordered_map <std::string, BASE*> myDevices;
...
for (auto& elem : myDevices ) {
elem->doSomething();
}
P.S: If you create the device objects dynamically, you could consider using unique or shared pointers in the map, to avoid memory leaks.
Upvotes: 2