c++ double dispatch with mirrored hierarchies
the following class hierarchies represent abstract resource handler and resource hierarchies. Both have the interfaces as base classes. Now imagine you write a system where you can implement multiple specific resource systems under these interfaces. Here is just one example. The specific main class creates the resources derived from stuff. Now开发者_运维问答 when the created resource is handed to the base interface it is handed as a pointer to the base resource class but i want to handle the specific resource and have access to its specific attributes.
I know about double dispatch, but i don't think it works in this case. I would like to prevent RTTI and dynamic_casts. Do you have suggestions as to handle such cases?
class resource;
class main_resource_handler
{
public:
virtual resource* create_resource() = 0;
virtual void do_some(resource* st) = 0;
};
class resource
{
};
class specific_resource : public resource
{
public:
int i;
};
class specific_resource_handler : public main_resource_handler
{
public:
stuff* create_resource) {
return new specific_resource);
}
void do_some(resource* st) {
// in here i want to work with specific resource
}
void do_some(specific_resource* st) {
// i want to get here
}
}
main_resource_handler* handler = new specific_resource_handler();
resource* res = handler->create_resource();
handler->do_some(res); /// here
I think you're not asking the right question.
To do what you're asking, all you need is to add this:
template<typename T>
class helper : public main_resource_handler
{
public:
virtual resource* create_resource() { return new T; }
virtual void do_some(resource* st) { do_some_specific(static_cast<T*>(st)); }
private:
virtual void do_some_specific(T* st) = 0;
};
And change this:
class specific_resource_handler : public helper<specific_resource>
{
private:
virtual void do_some_specific(T* st) { ... }
}
The static_cast
is only safe if you can guarantee that you will always call do_some
on the right type of handler. But if you already know it's the right kind of handler, then there's no need to make a base-class method call. So presumably what you want is to get some sort of resource
, not knowing its exact type, and pass it to the appropriate handler. That's trickier...
I wonder if the Curiously recurring template pattern is what you are looking for. There is already a thread on stackoverflow on this topic.
I'm not sure why you need both the resource and the handler - it seems you're exposing an extra coupling to something with would be encapsulated. The problem wouldn't exist if create resource just returned a resource that the client could call methods on directly.
If you want safety, have the resource remember the address of the handler which created it, then check that in do_some(resource* st)
. If the resource was created by the current handler, and a handler can only create resources of a given kind, then it's safe to cast it and call the specific function. Though as above, if the function was just a virtual function on the resource it would be by definition type safe.
I think you may be looking for this:
http://www.artima.com/cppsource/cooperative_visitor.html
精彩评论