1

I am trying to learn polymorphism and I am building a Shape hierarchy where a Shape class has two children namely TwoDimensionalShape and ThreeDimensionalShape. Again the TwoDimensionalShape has Circle, Square as children and ThreeDimensionalShape has Sphere, Cube as children. Here is my code till now.

public abstract class Shape
    {
    public abstract double area(); 
    }

public abstract class TwoDimensionalShape : Shape
    {
        public abstract override double area();
    }

public abstract class ThreeDimensionalShape : Shape
    {
        public abstract override double area();
        public abstract double volume();
    }

And I created Circle and Square classes under TwoDimensionalShape where I implemented the area method. Also I created Sphere and Cube classes under ThreeDimensionalShape where I implemented both area and volume methods. In my main method, I am trying to do this.

Shape[] myShapes = new Shape[4];
myShapes[0] = new Circle(4.0);
myShapes[1] = new Square(2.0);
myShapes[2] = new Sphere(8.0);
myShapes[3] = new Cube(6.0);

for (int i = 0; i < myShapes.Length; i++)
{
    Console.Write(myShapes[i].ToString());
    if(myShapes[i] is TwoDimensionalShape)
        Console.WriteLine(" : Area = {0}", myShapes[i].area());
    else if (myShapes[i] is ThreeDimensionalShape)
    {
        Console.Write(" : Area = {0}", myShapes[i].area());
        Console.WriteLine(" : Volume = {0}", myShapes[i].volume());
    }
}

Now I am getting an error that my Shape class does not contain any definition for 'volume'. So where do I put this volume method? I think I should put it in the Shape base class itself, but volume method is only specific to 3D Shapes right? Also why am I getting this error? I am only calling the volume method if myShapes[i] is ThreeDimensionalShape.

So where exactly should my volume method be?

John Mike
  • 147
  • 1
  • 14
  • Leave it where it is and cast to ThreeDimensionalShape before working with the shape: `if (myShapes[i] is ThreeDimensionalShape) { ThreeDimensionalShape 3dShape = myShapes[i] as ThreeDimensionalShape; ...Console.WriteLine(" : Volume = {0}", 3dShape .volume());` – TaW Jul 09 '16 at 06:29
  • 1
    Congratulations, you just self discovered a common pitfall/challenge when using inheritance. Could volume be considered 0 for 2D shapes? The moment you start casting inside your loop, you start violating the [open/closed principle](https://en.wikipedia.org/wiki/Open/closed_principle) among other things.. – Trevor Ash Jul 09 '16 at 06:36
  • @TrevorAsh Yes I think we could consider volume as zero for 2D Shapes, so in that case putting volume under shape's base class is better? – John Mike Jul 09 '16 at 06:40
  • I'm not sure the answer to my question leads to good advice, but sure, if you're comfortable with that expectation then you could put it on the base class. The only "good" in the solution is that it avoids the need to cast. That's a pretty good "good". Unless it leads to further code that says "If volume == 0 DoX() else DoY()" – Trevor Ash Jul 09 '16 at 06:42
  • @TrevorAsh No I do understand what you are telling, but in that case what would the preferred solution be? I mean in this case I guess I could put volume under base class and finish it, but there maybe a certain program where I may not be able to add a method such as this under base class, then what would be the best possible course of action? – John Mike Jul 09 '16 at 06:43
  • @Blasttrash I tend to favor what's referred to as composition, instead of inheritance. Take a look [here](http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance). For the sake of your learning exercise, I think you've done an exceptional job btw. – Trevor Ash Jul 09 '16 at 06:45
  • While I agree about a) composition being the more practical way to use OOP and b) avoiding casts is a good thing I also wonder c) how composition could help in this case and d) the if clause `if (myShapes[i] is ThreeDimensionalShape` isn't already probing the cast, so doing it is not at all making anything worse. - So the real OOP solution, short of avoiding inheritance (which may or may not be indeed be called for) is imo to give methods to the base class that will work in the kids. In this case one could define a 'printInfo' method where each child dumps all it knows about itself. Nice? No. – TaW Jul 09 '16 at 08:48
  • For German readers [here](http://www.heise.de/developer/artikel/Vererbung-fuer-Objekte-nuetzlich-fuer-Werte-gefaehrlich-3254433.html) is a nice article discussing the pitfalls of inheritance; it shows how there simply is no really 'correct' way to use inheritance for things like: __Circle <<==??>> Ellipse__ or __Point3D >>==??==>> Point2D__ or __float >>==??==>> complex__. The conclusion is that one can't succeed using _subclassing_ when one actually needs _subtyping_ – TaW Jul 09 '16 at 08:56

0 Answers0