You could do a dynamic_cast<OpenAble>
. This will throw an error if it is the wrong type though which is relatively expensive given that it is quite likely that the object will be the wrong type.
try{
OpenAble& opener = dynamic_cast<OpenAble&>(worldObj);
} catch (std::bad_cast& ex){
//not openable
}
BTW: As pointed out in the comments below, if you use a pointer to the base class in your container instead of references, then you can (and should) use the pointer version of dynamic_cast which will return a null in the case that your object is not OpenAble. Checking that in your case would be a lot more efficient than throwing and catching exceptions.
I would recommend an entirely different approach though. Inject your base class with an "OpenPolicy".
E.g.
class CanOpenPolicy {
public:
boolean canOpen(){ return true; };
boolean canClose(){ return true; };
boolean isOpen(){ return openState; };
void open(){ openState = OPEN; };
void close(){ openState = CLOSED; };
}
class NoOpenPolicy {
public:
boolean canOpen(){ return false; };
boolean canClose(){ return false; };
boolean isOpen(){ return CLOSED; };
void open(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
void close(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
}
//injection via template (no need for base "OpenPolicy" class, maybe some
// obscure error codes at compile though)
// Implicit interface based on how you use the injected policy.
template<OpenPol>
class WorldObject {
private:
// CTOR part of the injected contract so you are not tied to knowing how to
// build the policy. This is a key benefit over interface based injection.
OpenPol openPol;
...
public:
...
void open(){
if(openPol.canOpen()){
openPol.open();
}
}
...
}
That's not tested or anything. Just to illustrate the idea. You can add multiple policies for different possible operations and the best thing is that you won't need a lot of hierarchies.
To use it just do something like this:
std::unique_ptr<WorldObject>( new Chest() );
std::unique_ptr<WorldObject>( new Banana() );
std::unique_ptr<WorldObject>( new Chair() );
where:
class Chest : public WorldObject<CanOpenPolicy> {
// Very little implementation in here.
// Most of it is handled in the base class and the injected policies :)
}
class Banana: public WorldObject<CanOpenPolicy> {
}
class Chair : public WorldObject<NoOpenPolicy> {
}