www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Potentially stupid newbie question

reply Mr. Red <garfieldrules sbcglobal.net> writes:
Hi.  You might say I'm kind of a greenhorn programmer... I had just begun to
settle into C++ when I found out about D.  As such I understand the basics of
OOP, inheritance and that kind of thing, but there's one thing I can't figure
out.  Say I have a base class Cat.  Then I have derived (non-nested) classes
Tiger, Leopard, and Lion, all just derived from the base class Cat.  Then in my
program, I want to have an array of Cats to keep track of them all, and at any
one point in the program the exact species could change.  Now, I've tested and
found that:

Cat cat[10];

cat[0] = new Tiger();
cat[1] = new Leopard();
cat[2] = new Lion();
cat[3] = new Lion();

...
And so on and so forth, compiles, but I'm not able to access the member
functions of the derived class, even if I've set them to public.  What would I
do if I wanted to access the member functions?  I know that this is probably
something simple... Is there perhaps a better way to do what I'm trying to do
then the array approach?  

My compiler is GDC on OS X.
Aug 01 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Mr. Red" wrote
 Hi.  You might say I'm kind of a greenhorn programmer... I had just begun 
 to settle into C++ when I found out about D.  As such I understand the 
 basics of OOP, inheritance and that kind of thing, but there's one thing I 
 can't figure out.  Say I have a base class Cat.  Then I have derived 
 (non-nested) classes Tiger, Leopard, and Lion, all just derived from the 
 base class Cat.  Then in my program, I want to have an array of Cats to 
 keep track of them all, and at any one point in the program the exact 
 species could change.  Now, I've tested and found that:

 Cat cat[10];

 cat[0] = new Tiger();
 cat[1] = new Leopard();
 cat[2] = new Lion();
 cat[3] = new Lion();

 ...
 And so on and so forth, compiles, but I'm not able to access the member 
 functions of the derived class, even if I've set them to public.  What 
 would I do if I wanted to access the member functions?  I know that this 
 is probably something simple... Is there perhaps a better way to do what 
 I'm trying to do then the array approach?

When you say "access the member functions," are these functions that Cat defines? or functions only defined by the derived types? If the former, they should be accessible through the Cat type. i.e.: class Cat { void makeNoise() {writefln("meow");} } class Tiger { void makeNoise() {writefln("growl");} } class Lion { void makeNoise() {writefln("roar");} } cat[0].makeNoise(); // outputs growl cat[2].makeNoise(); // outputs roar If the latter, you need to downcast to the derived type. i.e.: Tiger t = cast(Tiger)cat[0]; // if cat[0] is not a Tiger, t will be null if(t !is null) t.doTigerThing(); Lion L = cast(Lion)cat[0]; ... -Steve
Aug 01 2008
parent reply Mr. Red <garfieldrules sbcglobal.net> writes:
I had been referring to when the methods were exclusive to the derived class,
but considering that in my would-be program the derived classes mostly just
redefine functions already present in the base class, the first method is
better.  I was just whipping up a quick test program with an unsophisticated
hierarchy and didn't think to include the base class's version of the function
too.  Thank you for your help!
Aug 01 2008
parent reply "Nick Sabalausky" <a a.a> writes:
"Mr. Red" <garfieldrules sbcglobal.net> wrote in message 
news:g6vv1i$1nu1$1 digitalmars.com...
I had been referring to when the methods were exclusive to the derived 
class, but considering that in my would-be program the derived classes 
mostly just redefine functions already present in the base class, the first 
method is better.  I was just whipping up a quick test program with an 
unsophisticated hierarchy and didn't think to include the base class's 
version of the function too.  Thank you for your help!

If you have an array of a base type (like Cat), it doesn't usually make much sense to try to access things that only exist in a derived type. This is because, for instance, you can be absolutely certain that "cat[someIndex]" is going to be a Cat, but you have no idea if it's also a Tiger or a Lion or whatever. So "someCat.doSomethingOnlyALionCanDo()" is risky business, because what if "someCat" isn't a Lion? Just because you put a Lion into myCat earlier in the program doesn't mean that later parts can be certain that that happened and is still true. Once in a while you will see cases where it's useful to say something like "Is this cat a Lion? If it's a Lion, do this special Lion-only thing on it". Polymorphism (ie: Steven's first part) is the usual/preferred way to handle this, when possible. But once in a while you might come across cases where that approach just isn't very applicable. In those cases, you can do RTTI (Run-Time Type Identification, ie, Steven's second part).
Aug 01 2008
parent JAnderson <ask me.com> writes:
Nick Sabalausky wrote:
 "Mr. Red" <garfieldrules sbcglobal.net> wrote in message 
 news:g6vv1i$1nu1$1 digitalmars.com...
 I had been referring to when the methods were exclusive to the derived 
 class, but considering that in my would-be program the derived classes 
 mostly just redefine functions already present in the base class, the first 
 method is better.  I was just whipping up a quick test program with an 
 unsophisticated hierarchy and didn't think to include the base class's 
 version of the function too.  Thank you for your help!

If you have an array of a base type (like Cat), it doesn't usually make much sense to try to access things that only exist in a derived type. This is because, for instance, you can be absolutely certain that "cat[someIndex]" is going to be a Cat, but you have no idea if it's also a Tiger or a Lion or whatever. So "someCat.doSomethingOnlyALionCanDo()" is risky business, because what if "someCat" isn't a Lion? Just because you put a Lion into myCat earlier in the program doesn't mean that later parts can be certain that that happened and is still true. Once in a while you will see cases where it's useful to say something like "Is this cat a Lion? If it's a Lion, do this special Lion-only thing on it". Polymorphism (ie: Steven's first part) is the usual/preferred way to handle this, when possible. But once in a while you might come across cases where that approach just isn't very applicable. In those cases, you can do RTTI (Run-Time Type Identification, ie, Steven's second part).

Just to add to what has already been said. You might want to research interfaces. Interfaces have no concrete body and people who inherit from it must implement all of is functions. They are often the better way to force the general shape of a type. By shape I mean that it will fit into things (functions etc...) that take that shape. At which point the concept of polymorphic becomes more powerful because you can re-use many patterns with different implementations and structures. -Joel
Aug 02 2008