TransWikia.com

Use virtual function to calculate area for different shapes C++

Stack Overflow Asked by Var_the_an on December 30, 2021

#include <iostream>
#include <fstream>
using namespace std;

class Shape
{
  public:
    string name;
    double width, height, radius;
  public:
    void set_data (double a, double b)
    {
        width = a;
        height = b;
    }
    virtual double area() = 0;
};

class Rectangle: public Shape
{
public:
    double area ()
    {
        return (width * height);
    }
};

class Triangle: public Shape
{
public:
    double area ()
    {
        return (width * height)/2;
    }
};

class Circle : public Shape
{
  public:
    double area ()
    {
        return 3.1415 * (radius * radius);
    }
};

int main()
{
    int N;
    cin >> N;

    Rectangle Rect;
    Triangle Tri;
    Circle Circ;
    string* S = new string[N];

    if(N == 1) {
      cin >> Rect.name >> Rect.height >> Rect.width;
      cout << Rect.area();

      return 0;
    } 
    else
{
    for(int i = 0; i < N; i++)
    {
        cin >> S[i];

        if(S[i] == "Rectangle")
        {
            cin >> Rect.height;
            cin >> Rect.width;
        }
         else if(S[i] == "Triangle")
             {
                 cin >> Tri.height;
                 cin >> Tri.width;
             }
             else if(S[i] == "Circle")
                  {
                      cin >> Circ.radius;
                  } 

    }
}
    cout << Rect.area() << " " << Tri.area() << " " << Circ.area();

  delete [] S;

    return 0;
}

the code works well in the Test 1 and Test 2, but in Test 3 give an error…
im need to input N number(count of Shapes) and display in Output all areas in ascending order…

For Example:

====== TEST #1 =======

Input:

1

Rectangle 4 3

Output:
12

The True Answer:
12

OK!

====== TEST #2 =======

Input:

3

Triangle 4 6

Rectangle 2 3

Circle 3

Output:
6 12 28.2735

The True Answer:
6 12 28.2735

OK!

====== TEST #3 =======

Input:

5

Triangle 4 6

Rectangle 2 3

Circle 4

Triangle 7 11

Triangle 3 5

Output:
6 7.5 50.264

The True Answer:
6 7.5 12 38.5 50.264

Error!

Please tell me, why my code is not working?

One Answer

Basically, the comments pointed the main issues, but I want to show a specific design for the abstraction:

Let's start with a concept for a shape property classes:

class shape_property {};

template <typename T>
concept ShapeProperty = std::is_base_of_v<shape_property, T>;

For the shape class (which accepts shape properties as template parameters):

template <ShapeProperty ...Properties>
class shape : virtual public Properties... {
public:
    explicit shape(std::string name) : name(std::move(name)) {}
    virtual ~shape() = default;

    [[nodiscard]] std::string get_name() const { return name; }

    virtual void input_data() = 0;
    [[nodiscard]] virtual double area() const = 0;

protected:
    std::string name;
};

Properties examples:

class width_shape_property : shape_property {
public:
    [[nodiscard]] double get_width() const { return width; }
    void set_width(double width) { this->width = width; }

protected:
    double width;
};

class height_shape_property : shape_property {
public:
    [[nodiscard]] double get_height() const { return height; }
    void set_height(double height) { this->height = height; }

protected:
    double height;
};

class radios_shape_property : shape_property {
public:
    [[nodiscard]] double get_radios() const { return radios; }
    void set_radios(double radios) { this->radios = radios; }

protected:
    double radios;
};

Shape examples:

class rectangle : public shape<width_shape_property, height_shape_property> {
public:
    rectangle() : shape("Rectangle") {}

    void input_data() override {
        double width, height;
        std::cout << "Enter width & height:" << std::endl;
        std::cin >> width >> height;
        set_width(width);
        set_height(height);
    }

    [[nodiscard]] double area() const override {
        return width * height;
    }
};

class triangle : public shape<width_shape_property, height_shape_property> {
public:
    triangle() : shape("Triangle") {}

    void input_data() override {
        double width, height;
        std::cout << "Enter width & height:" << std::endl;
        std::cin >> width >> height;
        set_width(width);
        set_height(height);
    }

    [[nodiscard]] double area() const override {
        return (width * height) / 2;
    }
};

class circle : public shape<radios_shape_property> {
public:
    circle() : shape("Circle") {}

    void input_data() override {
        double radios;
        std::cout << "Enter radios:" << std::endl;
        std::cin >> radios;
        set_radios(radios);
    }

    [[nodiscard]] double area() const override {
        return M_PI * radios * radios;
    }
};

Now, to contain the shapes in a single container, I used @MarkGarcia solution, which based on @SeanParent talk "Inheritance Is The Base Class Of Evil" with some minor modifications:

class virtual_base {
public:
    template<typename T>
    virtual_base(T &obj) : m_obj(std::make_shared<impl<T>>(obj)) {}

    void input_data() {
        m_obj->input_data();
    }

    [[nodiscard]] double area() const {
        return m_obj->area();
    }

private:
    class interface {
    public:
        virtual ~interface() = default;
        virtual void input_data() = 0;
        [[nodiscard]] virtual double area() const = 0;
    };

    template<typename T>
    class impl : public interface {
        T& m_impl_obj;

    public:
        explicit impl(T& impl_obj) : m_impl_obj(impl_obj) {}

        void input_data() override {
            m_impl_obj.input_data();
        }

        [[nodiscard]] double area() const override {
            return m_impl_obj.area();
        }
    };

    std::shared_ptr<interface> m_obj;
};

And the result:

int main() {
    std::vector<virtual_base> shapes;

    rectangle r;
    triangle t;
    circle c;

    shapes.emplace_back(r);
    shapes.emplace_back(t);
    shapes.emplace_back(c);

    for (auto &shape : shapes) {
        shape.input_data();
        std::cout << shape.area() << std::endl;
    }

    r.set_width(10);
    std::cout << shapes[0].area() << std::endl;

    return EXIT_SUCCESS;
}

Required headers:

#include <iostream>
#include <vector>
#include <memory>
#include <math.h>

For the github repository of the updated code.

Answered by CoralK on December 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP