Search code examples
c++classinheritancescope

How to simplify this code where a variable is declared after an user input in c++?


I wrote the following code :

#include <iostream>
using namespace std;

class Shape {
    public : float lgth;
    public : void getLgth() { cin >> lgth;}
};

class Square : public Shape {
    public : float calcArea() { return lgth * lgth; }
};

class Circle : public Shape {
    public : float calcArea() { return 3.14 * lgth * lgth; }
};

int main() {
    char shape_type;

    cout <<"Shape Type (c/s) ? ";
    cin >> shape_type;
    if (shape_type == 'c') {
      Circle my_shape;
      cout << "Shape Length ? ";
      my_shape.getLgth();
      cout << "Shape Area : " << my_shape.calcArea() << endl;
    }
    else if (shape_type == 's') {
      Square my_shape;
      cout << "Shape Length ? ";
      my_shape.getLgth();
      cout << "Shape Area : " << my_shape.calcArea() << endl;
    }

    return 0;
}

As the type of shape is not known at the beginning of the execution (it is asked to user), the variable my_shape is declared in an if then else statement. After this variable is only known in this scope (I understand this point). So, this part of code :

  cout << "Shape Length ? ";
  my_shape.getLgth();
  cout << "Shape Area : " << my_shape.calcArea() << endl;

must be repeated twice in this example.(But more if many shape classes exist).

I am a beginner in C++ but I supposed it is not the best way to do it. Any suggestions would be welcome. Thanks


Solution

  • The typical solution is to create the object dynamically after you know what type you want to use, and use virtual methods to handle common interactions on the different types, eg:

    #include <iostream>
    using namespace std;
    
    class Shape {
        public :
            float lgth;
            virtual ~Shape() = default;
            void getLgth() { cin >> lgth; }
            virtual float calcArea() = 0;
    };
    
    class Square : public Shape {
        public :
            float calcArea() override { return lgth * lgth; }
    };
    
    class Circle : public Shape {
        public :
            float calcArea() override { return 3.14 * lgth * lgth; }
    };
    
    int main() {
        char shape_type;
        Shape* my_shape;
    
        cout << "Shape Type (c/s) ? ";
        cin >> shape_type;
    
        if (shape_type == 'c') {
            my_shape = new Circle;
        }
        else if (shape_type == 's') {
            my_shape = new Square;
        }
        else {
            cout << "Unknown type!" << endl;
            return -1;
        }
    
        cout << "Shape Length ? ";
        my_shape->getLgth();
        cout << "Shape Area : " << my_shape->calcArea() << endl;
    
        delete my_shape;
    
        return 0;
    }
    

    Note, in modern C++, you should use smart pointers, like std::unique_ptr, instead of using new/delete directly, eg:

    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Shape {
        public :
            float lgth;
            virtual ~Shape() = default;
            void getLgth() { cin >> lgth; }
            virtual float calcArea() = 0;
    };
    
    class Square : public Shape {
        public :
            float calcArea() override { return lgth * lgth; }
    };
    
    class Circle : public Shape {
        public :
            float calcArea() override { return 3.14 * lgth * lgth; }
    };
    
    int main() {
        char shape_type;
        unique_ptr<Shape> my_shape;
    
        cout << "Shape Type (c/s) ? ";
        cin >> shape_type;
    
        if (shape_type == 'c') {
            my_shape = make_unique<Circle>();
        }
        else if (shape_type == 's') {
            my_shape = make_unique<Square>();
        }
        else {
            cout << "Unknown type!" << endl;
            return -1;
        }
    
        cout << "Shape Length ? ";
        my_shape->getLgth();
        cout << "Shape Area : " << my_shape->calcArea() << endl;
    
        return 0;
    }