Quetion regarding polymorphism

Hello,
I was thinking about this. If we have two classes, let's say Circle and Triangle,
it'll be best to put the common things in a base class. And make it abstract.
For example :
1
2
3
4
5
6
7
class Shape
{
public:
   virtual void draw();
   virtual void getX();
   virtual void getY();
}


1
2
3
4
5
6
7
8
9
10
class Circle : public Shape
{
public:
   void draw() { //draw it}
   double getX() { return x;}
   double getY() {return y;}
private:
   double x;
   double y;
}


1
2
3
4
5
6
7
8
9
10
11
class Triangle: public Shape
{
public:
   void draw() { //draw it}
   double getX() { return x;}
   double getY() {return y;}
   void anotherMethod() {// do something specific here};
private:
   double x;
   double y;
}


And of course, we use them this way :

Shape *shape = new Triangle();

So here we'll not have problems calling the draw(), getX() and getY() methods.
But how to call anotherMethod() ? I think this method will not be visible to the pointer of type Shape, even if the object it contains is of type Triangle. What do you think ?

Thank you in advance.
Last edited on
You're right. From a pointer to Shape you can't call anotherMethod. You can call it from a pointer to Triangle or from a Triangle object
Yes, but I though the idea is to use a pointer to base class, which points to some derived class in order to use only one method which accepts a pointer to that base class. And inside this method the late binding takes a place and decides which method should be called.
Then if I place the constructor of Triangle in private and create a static method which returns a pointer to the base class which points to Triangle :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Triangle: public Shape
{
public:
   static Shape* getInstance()
  {
      return new Triangle();
  }

   void draw() { //draw it}
   double getX() { return x;}
   double getY() {return y;}
   void anotherMethod() {// do something specific here};
private:
   Triangle(); // the constructor is now private

   double x;
   double y;
}

or something like this

How can I use the Triangle anotherMethod() ?
Yeah, I guess I'll have to cast it or something... whatever.
If you want to use another method, yes.
This is a design issue. Remember that inheritance is a one-way relationship (for the most part). All triangles are shapes, but not all shapes are triangles. Just because you have a parent class, doesn't mean you should always use a pointer to the parent class. If you're dealing with the child class specifically, then use the child class directly.

For example... this code you posted makes me raise an eyebrow:
1
2
3
4
5
6
7
class Triangle: public Shape
{
public:
   static Shape* getInstance()
  {
      return new Triangle();
  }


because getInstance is not only specific to Triangle, but also static it must be explicitly invoked with the Triangle classname. IE: shape = Triangle::getInstance();. Yet you're returning a Shape and not a Triangle! If the object cannot be created abstractly, then it makes no sense to return an abstract pointer. This discards information prematurely. Obviously code that is calling this function knows that the object is a Triangle, so why not use a Triangle pointer?

Ex:

1
2
3
4
5
6
7
8
9
   static Shape*  getInst_Shape()  // bad
   {
      return new Triangle();
   }

   static Triangle* getInst_Tri()  // good
   {
      return new Triangle();
   }


1
2
3
4
5
6
7
8
9
// I want to make a triangle and call anotherMethod()

Triangle* foo = Triangle::getInst_Tri();
foo->anotherMethod();  // easy peasy

// but if the getInstance function is needlessly abstracted, I need more work:

foo = static_cast<Triangle*>(Triangle::getInst_Shape());
foo->anotherMethod();


The latter bit is redundant. The cast shouldn't have to be necessary. It's already implied that the object is a triangle by the fact that I'm calling a Triangle member function.

Just because you can make a Triangle a Shape, doesn't mean you should.

------------------------ in that same vein...

If you're writing code that uses generic Shapes, then you shouldn't be calling anotherMethod because anotherMethod requires the object be a Triangle (and not any other kind of shape). Code that assumes the object is a Triangle should be using a Triangle* instead of a Shape*.

You should not be writing code which uses abstract objects such as Shape*, but assumes they are a specific type of shape. Any code that takes a Shape* should work with any kind of shape or else your code should be reorganized.

If you are using Shape* and discover that the shape is in fact a triangle, you should then be using a Triangle* and should no longer be using a Shape*.
Put it in simple language.

Let's say you have a function that receives a Shape object (well, a derived class that can be instantiated because shape is abstract):
1
2
3
4
void SomeFunc(Shape *pShape)
{
    ...
}


This means that SomeFunc knows how to perform certain operations on any shape, right? If you follow this thought, you will realize that SomeFunc() has no business in trying to decypher if Shape is Triangle or not, and therefore SomeFunc() should not care about the fact that maybe pShape points to a Triangle object because its sole purpose can be fulfilled by any shape, not just some shapes.

Does a paper shredder care if the paper being shred is Letter of A4? No. It shreds paper. Period.

If you are passing a pointer of type Shape is because you have no business with any of its specializations.

If you find a function in your code that attempts to do something special to some shapes, then your design is wrong.
Topic archived. No new replies allowed.