I’m trying to compare objects of a common base class together. The comparison should fail (output a failure string, for instance) in any case when the two objects differ in class, or differ in values specific to the object. Ideally the comparison is somehow enforced, such that a new derived class would also have to write a comparison function to members of its class. Here’s a code example:
#include <iostream>
#include <string>
#include <vector>
class Vehicle
{
public:
virtual std::string compareTo(Vehicle* v) = 0;
};
class Bicycle : public Vehicle
{
public:
Bicycle() { color_ = "red"; }
std::string compareTo(Vehicle* v) { return "We're different vehicles."; }
std::string compareTo(Bicycle* b) { return color_.compare(b->color_) ? "We're different bicycles." : "We're the same bicycle."; }
private:
std::string color_;
};
class Car : public Vehicle
{
public:
Car() { style_ = "sedan"; }
std::string compareTo(Vehicle* v) { return "We're different vehicles."; }
std::string compareTo(Car* c) { return style_.compare(c->style_) ? "We're different cars." : "We're the same car."; }
private:
std::string style_;
};
int main()
{
Vehicle* compareFrom = new Bicycle();
std::vector<Vehicle*> compareTos;
compareTos.push_back(new Bicycle());
compareTos.push_back(new Car());
std::vector<Vehicle*>::iterator it;
for (it = compareTos.begin(); it != compareTos.end(); ++it)
std::cout << compareFrom->compareTo(*it) << std::endl;
return 0;
}
Currently, the output (which you can see here) says “We’re different vehicles”. I know this is happening because I’m using the abstract base pointer. The problem is how to fix it!
The output I’d like to have is that the bicycles output that they’re the same, because they do have the same color. Bicycles and cars should output that they’re different vehicles. Bicycles of different colors and cars of different styles should also output that they’re different. I feel like there must be a great pattern to use to solve this problem, but I’m getting mired in dynamic casting or unsafe downcast issues. Also, I would like for the comparison function to be enforced among members of the same class (so Bicycles must be able to compare to other Bicycles).
You want Multiple Dispatch (i.e. select which function to call dynamically based on more than one variable, not just ‘this’). This is because you need to inspect the type somehow, otherwise the compiler will do a static analysis on the types and select what function to call (The virtual one in Vehicle).
No way around that.
dynamic_castis your friend here, but you may want to roll your own RTTI system for performance (or other) reasons. (The wikipedia article shows one way..)There is an implementation of this pattern in the Loki C++ library which might help if you have many types that need comparing.
Multiple dispatch is not supported by the language in C++, nor in most mainstream languages. There was a proposal to add it to C++11 though, see this question and Bjarne’s paper. I think it was rejected because (known and unknown) issues with dynamic linking, which the C++ standard sadly knows nothing about.