3

I was asked to implement this chart in polymorphism, which the output is to calculate geometry:

The criteria is as follows:

  • print() and getArea() function are placed in base class, which is Shape. It is also asked that it's a pure virtual function but I'm starting to doubt it(..?)
  • getPerimeter() function is placed in 2d class, and getVolume() is placed in 3d class
  • Each child of dimension shape has getArea() and getPerimeter() or getVolume(), depends on the dimension, which its function is to calculate

Here's the snippet of what I've done. To shorten, I'll put 2d class as an example:

//base initiation
    class Shape{
public: 
    virtual void print(){};
    virtual void getArea(double n){};
};

//2d class which is derived from base class
class TwoDimensionalShape : public Shape{
public:
    virtual void getPerimeter(double n){};
};

//The actual shape
class Circle : public TwoDimensionalShape{
protected: 
    double perimeter, area;
public:
    void getArea(double radius){
         this->area=(3.1415*radius*radius);
    }
    void getPerimeter(double radius){
        this->perimeter=(3.1415*2*radius);
    }
    void print(){
        cout << "Circle's perimeter: " << this->perimeter << endl;
        cout << "Circle's area: " << this->area << endl;
    }
    Circle(){};
    ~Circle(){};
};

And for the usage itself is:

//setting the object as global
Shape *object;
//the class
void circle(){
    Circle circle;
    object=&circle;
    double radius;
    system("cls");
    do{
        cout << "Enter radius value: ";
        cin >> radius; flush();
    } while (radius<=0);
    object->getPerimeter(radius); object->getArea(radius);
    object->print(); cin.get();
}

And I think I did it okay, but not! The error list shows:

Error   4   error C2039: 'getPerimeter' : is not a member of 'Shape'
Error   5   IntelliSense: class "Shape" has no member "getPerimeter"    

I was thinking about using cast, but I plainly have no experience with it.

Long story short, how do I able to access any kind of derived class only by using Shape *object (This object is also used for sphere, cube, tetrahedron, etc)?

p.s. this is not a duplicate of What should the TwoDimensionalShape Class contain? as it asks a totally different thing

EDIT 1: Yeah the signatures suck so I will edit my code in my desktop later as well as this one so please continue. Thanks!

  • 1
    You need to cast down to the derived class since that method is not on the base class `static_cast(object)->GetPerimeter(radius)` – Cory Kramer Jun 01 '17 at 13:32
  • 3
    Your `get` functions have terrible signatures. Getters should **return** the computed values. If your intention is to store their results (which isn't a very good idea), they should be called `calculateX` or `computeX`. – Bartek Banachewicz Jun 01 '17 at 13:33
  • @CoryKramer the static way works and I will try it soon along with dynamic cast. Thanks! – Nicholaus Cjj Jun 01 '17 at 14:48
  • @Bartek Whoops. Edited. (My friend complains about this too) – Nicholaus Cjj Jun 01 '17 at 14:48

4 Answers4

2

how do I able to access any kind of derived class only by using Shape *object

You can't. If you know that something is a two-dimensional shape, you should access it via such interface (doesn't really matter whether you upcast &circle into a 2D shape pointer or downcast the Shape pointer, in this particular example at least). The base Shape class doesn't have getPerimeter function and correctly won't allow you to use it.

Bartek Banachewicz
  • 36,624
  • 6
  • 81
  • 129
  • I actually have done the whole program using two objects, each assigned to the respective dimension. Thanks for this answer! – Nicholaus Cjj Jun 01 '17 at 14:56
1

So let me pick apart what you have said:

print() and getArea() function are placed in base class, which is Shape. It is also asked that it's a pure virtual function but I'm starting to doubt it(..?)

From your code you don't know what a pure virtual is, any class with a pure virtual becomes whats called an abstract base class, a keynote about an abstract base class is that you cannot create an instance of it and every class that inherits from it has to overwrite these functions, you make a pure virtual function by doing the following:

class Shape{
public: 
    virtual void print() = 0;
    virtual double getArea() = 0;
};

getPerimeter() function is placed in 2d class, and getArea() is placed in 3d class

getArea() and getPerimeter() are you sure its not suppose to be getVolume() and getPerimeter(), as those would make sense to be in the children classes, based on your third requirement. getArea() would already exist in the 3d class as the 3d class has to overwrite it and so does the 2d class.

Long story short, how do I able to access any kind of derived class only by using Shape *object (This object is also used for sphere, cube, tetrahedron, etc)?

Simply put, you don't as your Shape* will have no idea as to what getPerimeter() is or what getVolume() as they were not defined in the base class. You do have the option of using a temporary TwoDimensionalShape* and dynamically casting object to that, and then using that temporary pointer to get the perimeter.

Like:

TwoDimensionalShape* ptr_shape = dynamic_cast<TwoDimensionShape*>(object);
if(ptr_shape)
{
    ptr_shape->getPerimeter(/*arguments here if you have them...*/)
}
AresCaelum
  • 1,518
  • 1
  • 13
  • 18
  • Alright, I understand the concept of pure virtual function. For the dynamic cast itself, can I declare it without initializing a new object? That is, only casting the Shape *obj to TwoDimensionalShape and assign it to &circle so it will look like (based on my code) `dynamic_cast(obj); obj=&circle` – Nicholaus Cjj Jun 01 '17 at 15:01
  • you can do `dynamic_cast(obj)` and call the `TwoDimensionShape*` directly from that cast, the reason you you catch the value and do the if check is to make sure it was a valid conversion, however you cannot use `obj->getPerimeter()` as obj is still a Shape* and Shape does not know about `getPerimeter()`. – AresCaelum Jun 01 '17 at 18:28
0

First of all if your base class is abstract your methods should looks like this :

class Shape {
public: 
    virtual void print() = 0;
    virtual double getArea() = 0;
};

Then the childs class can have there own pure virtual method

getVolume or getPerimeter

class TwoDimensionalShape : public Shape{
public:
    virtual double getArea() { return getPerimeter(); }
    virtual double getPerimeter() = 0;
};

And Circle can now implements the method getPerimeter and use it's own value to compute the perimeter

class Circle : TwoDimensionalShape {
private:
    float m_radius;

public: 
    virtual double getPerimeter() { return 2.0 * PI * m_radius; }
};
jbalestr42
  • 64
  • 6
0

You need do a safe down cast, use dynamic_cast.

TwoDimensionalShape* shape_eddge = dynamic_cast<TwoDimensionalShape*>(circle);
if (shape_eddge)
  shape_eddge->getPerimeter()

http://en.cppreference.com/w/cpp/language/dynamic_cast

  • This actually won't work, as Object is still a Shape* and still wouldn't know about the getPerimeter() function. You would have to use a TwoDimensionShape* shape2 = dynamic_cast(object); if (shape2) shape2->getPerimeter() for this to work. – AresCaelum Jun 01 '17 at 13:48
  • ho yes i forget, i modif it now, ty Eddge – Cyril LOUISIN Jun 01 '17 at 13:55