Sign in to follow this  
sipickles

Testing for inheritance

Recommended Posts

sipickles    240
Hi, Can anyone remind me of the method, in C++, to test if a derived object is derived from a particular base object? It is trivial in Python. Eg:
class BaseObject
{
..
};

class DerivedObject: public BaseObject 
{
..
}

DerivedObject d;

if ( d ......is derived from BaseObject........ )
 print "d is derived from BaseObject" 
else
 print "Its not"


thanks Si

Share this post


Link to post
Share on other sites
SiCrane    11839
If you absolutely must do so, you can use dynamic_cast to cast to a base pointer type at runtime, or something like boost::type_traits::is_base_of at compile time. However, in general, it's a better idea just not to lose that kind of type information in the first place.

Share this post


Link to post
Share on other sites
kindjie    290
You would use a dynamic_cast and check for null.

Generally speaking, when you need to start casting to subtypes you have an LSP violation.

In your example, BaseObject should have a virtual function called print() which is implemented in DerivedObject. Then you can simply call print() on the BaseObject pointer and get the correct behaviour.

If your design doesn't allow this, then your DerivedObject - BaseObject relationship probably doesn't satisfy the is-a relationship, and you should look at alternatives like aggregation/composition or private inheritance.

Share this post


Link to post
Share on other sites
sipickles    240
So designs which use MI to assign properties are mistaken. Eg:

class Clickable {};

class Dragable {};


class ClickableDragableThing : public Clickable, public Dragable {}

ClickableDragableThing thing;

if ( thing == dragable() )
StartDrag();


Thats not real c++ code btw ;)


Share this post


Link to post
Share on other sites
Lode    1003
Yeah, dynamic_cast is what you want. I thought RTTI was fairly standard, which compiler doesn't enable that by default?

I sense the anti-dynamic_castness is quite big in this thread. However, while I wouldn't advice to use it always, I find it can be very nice in some cases, while having code that is easily maintainable even in large projects on which lots of people work.

E.g. if you have some database of items and you want to get items of a certain type: go over all items, dynamic cast to check if it's the type you want, if yes, add it to the result vector.

Multiple inheritence can also give designs that are perfectly understandable and maintainable, and can avoid code duplication, and in combination with dynamic casts you get a very nice toolbox.

C++ is not Java :)

Why would those things be bad?

Share this post


Link to post
Share on other sites
sipickles    240
I like the boost is_base_of idea. It fits my thinking, but maybe I've been working in Python world for too long where programming is actually logical!

Coming back to C++ is like detaching part of my brain and plugging in a PCB :-)

MI seems so powerful to me, yet so hated. Not sure I get why (yet!)

Share this post


Link to post
Share on other sites
Vorpy    869
C++ is statically typed, so the only time you can have a derived object and not already know its base classes from its class is if you're trying to do a cast to a "cousin" or if you're doing template programming.

A cousin would be something like this:

class Base1{};
class Base2{};
class Derived : public Base1, public Base2{};

Base1 *b1 = new Derived();
Base2 *b2 = dynamic_cast<*Base2>(b1);

if (b2)
cout << "b1 points to a class derived from base2";
else
cout << "b1 does not point to a class derived from Base2";




With templates, you can use partial specialization.

Dynamic casts are discouraged because the result is often difficult to maintain, as logic dealing with different classes gets distributed throughout the code, instead of being encapsulated within the class definitions.

This is true in python as well, where the idiom is to assume the object supports the operations you are performing on it. For example, any function that works on "file-like objects" will work on any object that implements the same methods as files. If the functions checked to make sure the objects were actually files, then the code wouldn't work on non-file objects, but this needlessly reduces the usefulness of the code.

Share this post


Link to post
Share on other sites
Aface    124
The feeling i get is that MI is treated with caution because inheriting from anything but fairly trivial multiple base classes quickly becomes quite a convoluted mess thats very hard to maintain. I'd have to agree with this.

As to your original question - the question itself leads me to believe you might want to rethink the way you structure your code. I don't believe inheritance (or at least the part of inheritance your using) was designed to give the information your trying to wrestle out of it - It is more to change the behaviour of an object without changing the interface.

To give you a pseudocode example, I have written a gui system where i have a base Window class. It has several virtual functions including :OnDrag(int iX, int iY), and :OnClick(int iX, int iY); These virtual functions are defined as doing nothing in the base class, and then i can derive a DraggableWindow from this window class, and all i need to do is implement these functions for draggable objects, and also (if needed) the click function.

Alex

Share this post


Link to post
Share on other sites
sipickles    240
Ok, I admit defeat, since I 've not heard one voice supporting MI. I concur that my structure stretches the bounds of encapsulation, but my MI structure is all based around one _type_ of object.

In reality, I am dealing with game objects, where I hoped to make several base classes which all objects derive from in various combinations. Each base class assigns an attribute like:

Selectable
Intelligent
Mobile
Container
etc

So I gather I should look at other approaches. By this we mean nested classes right?

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by sipickles
So I gather I should look at other approaches. By this we mean nested classes right?


Not "nested" (which implies nesting of the actual class definitions) but "composed" or "aggregated".

Share this post


Link to post
Share on other sites
Nitage    1107
Quote:
to test if a derived object is derived from a particular base object


WHAT? You're all recommending dynamic_cast? A derived object can ALWAYS be cast to a base object. That's an OO fundamental.

If you're asking whether a random object can be cast to a random base, then you're
doing something wrong.

Share this post


Link to post
Share on other sites
SiCrane    11839
Quote:
Original post by Nitage
Quote:
to test if a derived object is derived from a particular base object


WHAT? You're all recommending dynamic_cast? A derived object can ALWAYS be cast to a base object. That's an OO fundamental.


struct A {};
struct B {};
struct C : A, B {};

A * a = new C;
B * b = a; // compile error.

Share this post


Link to post
Share on other sites
sipickles    240
Quote:
Original post by Nitage
If you're asking whether a random object can be cast to a random base, then you're doing something wrong.


I was actually asking if I could test whether an object (derived through MI from several bases) was derived from a particular base, ie, Is object 'tree', selectable? (has it derived from base object SelectableObject, and therefore possesses appropiate attributes?)

Thanks for all the advice, but I confess to being a little confused. Composition doesn't seem to fit my requirements.

Lode seemed to support my MI theory. I want to be able to have a general list of local game objects, something like this:


class BaseObject
{
// pos, mesh etc
};
class MobileObject
{
// speed, turn(), move() etc
};


class Rock : public BaseObject {};
class FastShip : public BaseObject, public MobileObject {}

std::map< int, boost::shared_ptr<BaseObject> > inGameObjects;

boost::shared_ptr<Rock> boringRock = boost::shared_ptr<Rock>(new Rock);
boost::shared_ptr<FastShip> pirate = boost::shared_ptr<FastShip>(new FastShip);

inGameObjects[1003] = boringRock;
inGameObjects[22] = pirate;

////

std::map< int, boost::shared_ptr<BaseObject> >::iterator iter;

for ( iter = inGameObjects.begin(); iter != inGameObjects.end(); iter++ )
if ( boost::is_base_of<MobileObject, iter.second> == boost::true_type )
iter.second->move();






Go on then... do your worst! ;)

Share this post


Link to post
Share on other sites
sipickles    240
Ah, I think I have it.....

Instead I want something like this:


class CommonProperties
{
// pos, mesh etc
};
class MobileProperties
{
// speed, turn(), move() etc
};


class GameObject
{
public:
GameObject() { m_common = boost::shared_ptr<CommonProperties>( new CommonProperties ); }

MakeMobile() { m_mobile = boost::shared_ptr<MobileProperties>( new MobileProperties ); }
boost::shared_ptr<MobileProperties> IsMobile() { return m_mobile; }


private:
boost::shared_ptr<CommonProperties> m_common;
boost::shared_ptr<MobileProperties> m_mobile;
};


std::map< int, boost::shared_ptr<GameObject> > inGameObjects;

boost::shared_ptr<GameObject> boringRock = boost::shared_ptr<GameObject>(new GameObject);

boost::shared_ptr<GameObject> pirate = boost::shared_ptr<GameObject>(new GameObject);
pirate->MakeMobile();

inGameObjects[1003] = boringRock;
inGameObjects[22] = pirate;

////

std::map< int, boost::shared_ptr<GameObject> >::iterator iter;

for ( iter = inGameObjects.begin(); iter != inGameObjects.end(); iter++ )
if ( iter.second->IsMobile() )
iter.second->move();





Any better?

Should I be using weak_ptrs as return types from IsMobile()?

Thanks

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this