I know that you can store a bunch of Parent* objects in a vector. However, if the functions you need to call on the objects cannot be defined in the parent class (they depend on a template parameter of the subclass) then how are you supposed to retrieve the objects from the container?
In this example:
#include <iostream>
class ImageBase{};
template <typename TPixel>
class Image : public ImageBase
{
public:
TPixel GetPixel() const {TPixel a; return a;}
};
template<typename TImage>
void Output(const TImage* image)
{
std::cout << image->GetPixel();
}
int main(int, char *[])
{
// Works correctly
{
Image<float>* image = new Image<float>;
image->GetPixel();
Output(image);
}
{
ImageBase* image = new Image<float>;
Output(image);
}
return 0;
}
The Output(image); where ‘image’ is a ImageBase* fails (of course) because GetPixel is not defined in ImageBase. I know you can dynamic_cast<> to a bunch of types to figure out if the subclass matches any of them, but this list could very quickly get very long. The long list would be fine if it could reside in one place, but how would you make a function to do this? The function would take an ImageBase*, but what would it return?
returnType? GetSubclass(ImageBase* input)
{
if(dynamic_cast<Image<float>*>(input))
{
return Image<float>*;
}
else if(dynamic_cast<Image<int>*>(input))
{
return Image<int>*;
}
}
It seems reasonable to me to want to be able to call some template functions on subclasses that only vary in signature by their template parameter (as setup in this example), does it not?
In my real case, both Image and ImageBase are part of a library, so I cannot change them.
Visitor pattern to recover the type information, possibly with a templated helper implementing the
visitfunction.First, let’s make your algorithm into a polymorphic functor object:
Now, let’s add a visitor interface:
And a forwarder:
And a factory:
Now a visitor-compliant image wrapper:
Finally, you are able to use a polymorphic vector of images!
That was a lot of code, but the good thing is that new types can be added without affecting existing functors (just extend the shim) as long as the functor was implemented with a template. And not much code is needed to add more image processing functions (just a new template functor class, similar to
Output).