0

I have three classes: Shape, Rectangle and Circle. Shape is parent of two other class. definition of this classes is in following code:

#include <iostream>

using namespace std;

class Shape {
public:
    Shape() {

    }

    ~Shape() {

    }

    void set(float BORDER, string COLOR) {
        border = BORDER;
        color = COLOR;
    }

    double computeArea() {
        return 0;
    }

private:
    float border;
    string color;
};

class Circle : public Shape {
public:
    Circle() {

    }

    ~Circle() {

    }

    void setRadius(float RADIUS) {
        radius = RADIUS;
    }

    double computeArea() {
        return 3.14 * radius * radius;
    }

private:
    float radius;
};


class Rectangle : public Shape {
public:
    Rectangle() {

    }

    ~Rectangle() {

    }

    void setWidth(float w) {
        width = w;
    }

    void setLength(float l) {
        length = l;
    }

    double computeArea() {
        return width * length;
    }

private:
    float width;
    float length;
};

I build two object from Circle and Rectangle classes. Then I copied this two object into Shape class. When I run computeArea() function in following order I get 0 result.

#include <iostream>

using namespace std;

int main() {
    Circle c;
    c.setRadius(3);
    Rectangle r;
    r.setWidth(4);
    r.setLength(5);

    Shape sh[2];

    sh[0] = c;
    sh[1] = r;

    cout << sh[0].computeArea() << endl;
    cout << sh[1].computeArea();

    return 0;
}

I want compute area of all shapes with correct function. How can I do that?

Thanks in Advance

mshomali
  • 664
  • 1
  • 8
  • 27
  • 1
    For polymorphic behaviours, you need to either use pointers or references, plus you need to use `virtual` functions – Fureeish Dec 26 '18 at 16:09
  • @Fureeish I make `computeArea` function virtual but I still get 0. I want to copy child object to parent object and run `computeArea` function on `Shape` class – mshomali Dec 26 '18 at 16:15
  • 2
    You forgot about "*you need to either use pointers or references*". You cannot copy child object to parent object (you can, but the object will be [sliced](https://stackoverflow.com/questions/274626/what-is-object-slicing) and that's **not** what you want). However, you can *have a reference or a pointer of a parent type poining to child object*. That, paired with `virtual` functions, will result in expected behaviour. – Fureeish Dec 26 '18 at 16:17
  • @Fureeish Nice! Good point. – mshomali Dec 26 '18 at 16:23

3 Answers3

3

To expand on what Fureeish said, change your code to this:

int main() {
    Circle c;
    c.setRadius(3);
    Rectangle r;
    r.setWidth(4);
    r.setLength(5);

    Shape *sh[2];

    sh[0] = &c;
    sh[1] = &r;

    cout << sh[0]->computeArea() << endl;
    cout << sh[1]->computeArea();

    return 0;
}

and declare computeArea (and also Shape's destructor, in case you destroy a derived object through a pointer to the base class) as virtual.

Assigning a derived class to an object of the base class is known as 'object slicing' and usually leads to undesirable results. Using pointers (or references) avoids this.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • 2
    +1. Also worth to mention that usually when polymorphic behaviours are desired, it's good to declare destructors as `virtual` as well. – Fureeish Dec 26 '18 at 16:18
0

You seem to be missing the virtual keyword.

The destructor of the base class Shape needs to be virtual as well (in case you ever decide to manipulate any of the derived objects through a pointer to the base class).

The function computeArea() must be declared virtual, like this virtual double computeArea() { ... }.

#include <iostream>

using namespace std;

class Shape {
public:
    Shape() {

    }

    virtual ~Shape() {

    }

    void set(float BORDER, string COLOR) {
        border = BORDER;
        color = COLOR;
    }

    virtual double computeArea() {
        return 0;
    }

private:
    float border;
    string color;
};

class Circle : public Shape {
public:
    Circle() {

    }

    virtual ~Circle() {

    }

    void setRadius(float RADIUS) {
        radius = RADIUS;
    }

    virtual double computeArea() {
        return 3.14 * radius * radius;
    }

private:
    float radius;
};


class Rectangle : public Shape {
public:
    Rectangle() {

    }

    virtual ~Rectangle() {

    }

    void setWidth(float w) {
        width = w;
    }

    void setLength(float l) {
        length = l;
    }

    virtual double computeArea() {
        return width * length;
    }

private:
    float width;
    float length;
};

Also if you are using C++11 or newer, you can add the overrride keyword at endd of the computeArea function definitions, like this

    virtual double computeArea() override {
        return width * length;
    }

and this,

    virtual double computeArea() override {
        return 3.14 * radius * radius;
    }

in the respective classes.

And then modify the main function like this.

    int main() {
    Circle c;
    c.setRadius(3);
    Rectangle r;
    r.setWidth(4);
    r.setLength(5);

    Shape *sh1, *sh2;

    sh1 = &c;
    sh2 = &r;

    cout << sh1->computeArea() << endl;
    cout << sh2->computeArea();

    return 0;
}

EDIT: Also, as others have pointed out, you need pointers to the base class and don't need to copy your derived class objects to the base class object. See the modified main() function please.

Duck Dodgers
  • 3,409
  • 8
  • 29
  • 43
  • I make `computeArea` function virtual but I still get 0. I want to copy child object to parent object and run `computeArea` function on Shape class – mshomali Dec 26 '18 at 16:15
  • @mshomali If you call _computeArea_ on a _Shape_ the result will always be 0, the fact you created (copy) the _Shape_ from a child class is not relevant – bruno Dec 26 '18 at 16:23
  • @mshomali, I modified the `main()` function, so that you use pointers to the base class and not copy derived objects to a base-class object. – Duck Dodgers Dec 26 '18 at 16:27
0

In Shape class make computeArea() an abstract(or purely virtual) method:

virtual double computeArea() =0;
  • If I do it, I can't create any object from `Shape` class – mshomali Dec 26 '18 at 16:17
  • @mshomali of course, this is the goal of an abstract class, that force you to define the operation in the child classes – bruno Dec 26 '18 at 16:21
  • I think you can declare it as virtual(without the =0) and then use pointers for example: Shape* S(new Cercle()); double a=S->computeArea(); – Salma Halloumi Dec 26 '18 at 16:24
  • My purpose is compute area of all childs of `Shape` class one time on objects of `Shape` class. – mshomali Dec 26 '18 at 16:25
  • @mshomali in `Shape s1 = ...` _s1_ is a _Shape_ and cannot be a child class instance. In `Shape * s2 = ...` that time s2 can point to an instance of a child class or a _Shape_ because this is a pointer to, you do not create a new instance contrarily to _s1_ which is a new instance os _Shape_ – bruno Dec 26 '18 at 16:29