On inheritance and polymorphism in cats and dogs (and other beasts too)

Mike Parker via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Dec 21 07:05:46 PST 2014


On Sunday, 21 December 2014 at 10:42:37 UTC, Derix wrote:



If you change the mother and father parameters from Beasts to 
Cats, then you aren't overriding anything -- you are 
/overloading/. That's where the first two errors were coming 
from. In order for a subclass method to override a base class 
method, the signature has to be the same (same parameter types).

The error about pickiness was because you were trying to access 
mother.pickiness and father.pickiness even though mother and 
father are declared as Beasts -- Beasts don't have pickiness. To 
get at their pickiness you have to downcast them to Cats. Think 
of it as a 'view' of each object.

The mother and father parameters are declared as Beasts, so you 
can only "see" what a Beast has. You can't see anything that a 
Cat has through a Beast, because the Beast might actually be a 
Dog instead. So you have to create a new "view" by casting to the 
appropriate type. If the underlying object is not an instance of 
the type you cast to, the cast will return null and you can 
immediately return from the function, throw an error, or whatever 
you think is appropriate in that case.

class Cat : Beast
{
    protected override void mixGenetics( Beast mother, Beast 
father )
    {
       // The superclass works on Beasts, so give it the Beasts
       super.mixGenetics( mother, father );

       // This method needs cats, so cast to Cats
       Cat catmom = cast( Cat )mother;
       Cat catdad = cast( Cat )father;

       // If the casts failed, then mother and father are not 
Cats. Since
       // they are not Cats, you can't do anything Catty with 
them. So
       // either return from the function or throw an Error or 
something.
       if( catmom is null || catdad is null )
          throw new Error( "Expected cats, got something else." );

       // Now do Catty things
       pickiness = (mother.pickiness + father.pickiness) / 2;
    }
}

You never need a cast operator to cast up and down a class 
hierarchy. A Cat *is* a Beast, so you can always "upcast" without 
fear of failure. A Beast *might be* a Cat, so you can attempt a 
"downcast" when you must and the cast will return null if the 
underlying instance isn't actually a Cat.


More information about the Digitalmars-d-learn mailing list