Let's say I'm working on a library that works on items of type Item. The main entry point is a class like:
class Worker
{
private:
SomeContainer _c;
public:
void add( const Item &i );
void doSomething();
};
The doSomething()
method looks at the added items, compares them, etc. and does something with them. So the Item class needs an operator==
.
Now, I want to use this library in different environments and in each environment the implementation of the Item class is different. Therefore, Item needs a virtual comparison function:
class Item
{
protected:
virtual bool _equals( Item &other ) = 0;
public:
bool operator==( Item &other ) { return _equals( other ); };
};
And each environment has its own Item implementation. The library only knows about the Item class and the specific item classes are defined and implemented in the platform-specific applications using the library. In environment A it might be:
class AItem: public Item
{
private:
bool _equals( Item &other );
std::string _member;
...
};
and in environment B:
class BItem: public Item
{
private:
bool _equals( Item &other );
int _member;
...
};
What is now the best way to, for each environment, implement the comparison for use by the library? _equals
is specified in the Item class , so its specific item implementations need to cast other
to their own type.
In a given environment, different item types will not be used at the same time, so given that assumption, the following would be sort-of safe:
bool AItem::_equals( Item &other )
{
return this->_member == static_cast<AItem &>(other)._member;
}
But it seems like a nasty solution because it allows a programmer using the library to implement a new environment to break things if he adds items of different types to the worker.
Other solutions I can think of are:
- Use
dynamic_cast
. - Implement my own sort-of-RTTI by adding a member to the base Item class indicating the environment. This can then be used in the comparison function to see if
other
is of the same type. Not very elegant. - Implement all the types in the library and select the right one based on a
#define
at compile-time. This means the library itself must be extended for each environment. - Use a templatized worker.
But I feel there must be a more elegant solution. Maybe something completely different. What would you do?