Help needed regarding class files

So, I am the first to admit, I do not know how to word this that it may make sense to a seasoned C++ programmer. But I will do my best. I am trying to make a program to calculate the area of 3 shapes, each with their own class file. I have to make a virtual function getArea() which I've figured out. But I also have to include shapeID(), shapeType(), and unitOfMeasure() in the shape class to call in the individual shapes classes. With Shape.h and Shape.cpp being the overarching class file.

So here's my question. I want to make a function, in Shape.h, that is defined in the individual shape class files. Where shapeID() becomes a numeric value that I can call as menu options in main. And shapeType() is applied as what kind of shape it is in the menu, and subsequent output. The unitOfMeasure() can mimic shapeType() so I wouldn't need that if I could get pointed in the right direction on setting up those two, shapeID() and shapeType().

Just for an example, here is the files for what I currently have, and what I'm hoping to do with main.

Any help would be greatly appreciated.

Shape.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef SHAPE_H
#define SHAPE_H


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


    protected:

    private:

};

#endif // SHAPE_H 


Triangle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef TRIANGLE_H
#define TRIANGLE_H
#include "Shape.h"


class Triangle : public Shape
{
    public:
        Triangle(double base =0, double height =0);
        double getArea(){return base * .5 * height;};
        void shapeID(int x){x=1;};
        void shapeType(char Triangle);
        double getBase() const;
        double getHeight() const;
        void setBase(double base);
        void setHeight(double height);

    private:
        double base, height;
};

#endif // TRIANGLE_H 


Triangle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "Triangle.h"
#include <iostream>

using namespace std;

Triangle::Triangle(double b, double h)
{
    base = b;
    height = h;
}

double Triangle::getBase() const{
    return base;
}

double Triangle::getHeight() const{
    return height;
}

void Triangle::setBase(double b){
    base = b;
}

void Triangle::setHeight(double h){
    height = h;
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "Shape.h"
#include "Triangle.h"
#include <iostream>

using namespace std;

int main()
{
    Triangle t;
    double base, height, radius, length;
    int menu;

do {
    cout << endl <<  "Welcome to the area calculator, please select a shape to work with below, or press 0 to exit" << endl;
    cout << shapeID(menu) << ": " << shapeType() << endl;
}
k    cout << "Enter the base of the Triangle: ";
    cin >> base;
    t.setBase(base);
    cout << "Enter the height of the Triangle: ";
    cin >> height;
    t.setHeight(height);
    cout << "the area of the triangle is: " << t.getArea() << endl;

    return 0;
}


In main.cpp, I have the code working up to the Do loop I'm starting to write. I will be using a switch for the menu and would like shapeID() to populate that menu, with shapeType() to display what type of shape it is.

I hope this makes sense, and someone can assist me.

Thank you,
Sam
We call what you're doing object oriented programming.

You have an interface to your system of shapes, Shape, that defines a set of methods that each actual shape has.

Object orinted programming in C++ is implemented using indirection using pointers or references . You should not instantiate an object directly as you've done with Triangle. The Factory pattern is a stanadard way of creating objects indirectly based on some criteria, like your shape id.

Object methods are defined with virtual functions.

C++'s runtime type identification mechansim (RTTI) can tell you what type of class you have, so you can use that, or add a getName method to allow each shape to identify itself.

As you've said, your know what your shape header looks like:
1
2
3
4
5
6
7
8
9
10
#include <stirng>

class Shape
{
public:
    virtual ~Shape() = default;
    virtual int getId() const = 0;
    virtual std::string getName() const = 0;
    virtual double getArea() const = 0;
};

You can then implement individual shapes.
Triangle.hpp
1
2
3
4
5
6
7
8
9
class Triangle : public Shape
{
    double m_base, m_height;
public:
    Triangle(double base, double height) : m_base(base), m_height(height) {}
    virtual int getId() const { return 1; }
    virtual std::string getName() const { return "triangle" }
    virtual double getArea() const { return m_base*m_height*0.5; }
};

Square.hpp
1
2
3
4
5
6
7
8
9
class Square : public Shape
{
    double m_length;
public:
    Square(double length) : m_length(length) {}
    virtual int getId() const { return 2; }
    virtual std::string getName() const { return "square" }
    virtual double getArea() const { return m_length*m_length; }
};
Last edited on
If shapeID is supposed to return 1 (for example) for any triangle and 2 for a square, etc., then I think it's basically pointless.

Try something like this. I've written it so you can copy and paste it into one file to try it out. You'll have to uncomment the includes to put it into multiple files.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#ifndef SHAPE_H
#define SHAPE_H

class Shape {
    public:
        virtual ~Shape() = default;
        virtual const char *shapeType()     const = 0;
        virtual void        setProperties()       = 0;
        virtual double      getArea()       const = 0;
};

#endif // SHAPE_H 

//////////////////////////////////////////////////////////////////////////

#ifndef TRIANGLE_H
#define TRIANGLE_H
//#include "Shape.h"

class Triangle : public Shape {
    public:
        Triangle(double b=0, double h=0) : base(b), height(h) {}

        const char *shapeType() const {return "Triangle";}
        void setProperties();
        double getArea() const { return base * .5 * height; };

        double getBase()   const   { return base; }
        double getHeight() const   { return height; }
        void   setBase(double b)   { base = b; }
        void   setHeight(double h) { height = h; }
    private:
        double base, height;
};

#endif // TRIANGLE_H 

//////////////////////////////////////////////////////////////////////////

//#include "Triangle.h"
#include <iostream>
using namespace std;

void Triangle::setProperties(){
    double base, height;
    cout << "Enter the base of the Triangle: ";
    cin >> base;
    setBase(base);
    cout << "Enter the height of the Triangle: ";
    cin >> height;
    setHeight(height);
}

//////////////////////////////////////////////////////////////////////////

#ifndef SQUARE_H
#define SQUARE_H
//#include "Shape.h"

class Square : public Shape {
    public:
        Square(double l=0) : length(l) {}

        const char *shapeType() const { return "Square"; }
        void setProperties();
        double getArea() const { return length * length; }

        double getLength() const { return length; }
        void setLength(double l) { length = l; }
    private:
        double length;
};

#endif // SQUARE_H 

//////////////////////////////////////////////////////////////////////////


//#include "Square.h"
#include <iostream>
using namespace std;

void Square::setProperties(){
    double length;
    cout << "Enter the side length of the square: ";
    cin >> length;
    setLength(length);
}

//////////////////////////////////////////////////////////////////////////

//#include "Shape.h"
//#include "Triangle.h"
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<Shape*> shapes;
    shapes.push_back(new Triangle());
    shapes.push_back(new Square());

    while (true) {
        cout << "\nWelcome to the area calculator, please select a "
                "shape to work with below, or press 0 to exit\n";
        for (size_t i = 0; i < shapes.size(); i++)
            cout << i + 1 << ": " << shapes[i]->shapeType() << endl;

        int choice;
        cin >> choice;
        if (choice == 0)
            break;

        --choice;
        shapes[choice]->setProperties();
        cout << "the area of the " << shapes[choice]->shapeType()
             << " is: " << shapes[choice]->getArea() << endl;
    }

    return 0;
}

Last edited on
KBW~

You are a life saver, that makes complete sense. And seeing the examples is assuring that I was on the right track with what I was thinking. And your additional information about Factory patterns was very helpful, and looking at it makes sense.

I am very grateful for this information and will follow up if I had additional questions.

Thank you,
Sam
So, I do have a couple questions that I'm kind of stuck on.

1.) How would I call for the base and height in my main.cpp file? I'm trying to test, and everything I'm trying, it doesn't like. So it seems I'm missing something.

2.) How would I go about using shapeId(), or getId() as you noted, to be an input selection from the user to identify the switch menu cases?

I think, at this point, if I can understand those two calls, then I can figure the other errors I'm getting out. But am struggling to figure out how to do those two things.

Thank you,
Sam
At least try the program I posted. Just copy and paste it in a single file (just to try it).
Look at how the main loop works.
And note how the shapeID is not needed.
It's really a design mistake when you think about it.
The object shouldn't know it's position in the menu.
That's the menu's business.
tpb ~

Thank you, unfortunately, this is for an assignment, and I have to include shapeId() in the shape class file to be applied. While true, I don't need it, and can do the program without it. It's a requirement. I just thought a way to apply it would be to make it the menu options. If it can't be done, then that's fine, I can apply it somewhere else. But of course, it wasn't made clear in the instructions for the assignment what it was to be used for, or how it should be used.

Thank you,
Sam
tpb ~

Actually, you are on the money! Instead of shapeType() being the string, I can use that as the "setProperties()" and use shapeId() as what type of shape it is! I don't know why I didn't think of that before!

Sam
Okay, I see. You should maybe try to clarify from your prof how it was meant to be used.

Another possibility is that every separate shape object is supposed to have it's own id. E.g., when you make the first shape (no matter what it is) it gets id 1. The next shape (even if it's the same shape as the first, but a different object) gets id 2, etc.

If each shape class is supposed to have an id (so that all Triangles have the same id, all Squares the same id, etc.) then it should probably be a static (possibly const) member since it would be the same for all objects of that class.

But anyway, here's a simple way of using it as the menu number. Maybe it's not exactly what you need but hopefully it'll give you some ideas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifndef SHAPE_H
#define SHAPE_H

class Shape {
    public:
        virtual ~Shape() = default;
        virtual const char *shapeType()     const = 0;
        virtual void        setProperties()       = 0;
        virtual double      getArea()       const = 0;
        virtual int         shapeID()       const = 0;
};

#endif // SHAPE_H 

//////////////////////////////////////////////////////////////////////////

#ifndef TRIANGLE_H
#define TRIANGLE_H
//#include "Shape.h"

class Triangle : public Shape {
    public:
        Triangle(int id, double b=0, double h=0)
            : id(id), base(b), height(h) {}

        const char *shapeType() const {return "Triangle";}
        void setProperties();
        double getArea() const { return base * .5 * height; };
        int shapeID() const { return id; }

        double getBase()   const   { return base; }
        double getHeight() const   { return height; }
        void   setBase(double b)   { base = b; }
        void   setHeight(double h) { height = h; }
    private:
        int id;
        double base, height;
};

#endif // TRIANGLE_H 

//////////////////////////////////////////////////////////////////////////

//#include "Triangle.h"
#include <iostream>
using namespace std;

void Triangle::setProperties(){
    double base, height;
    cout << "Enter the base of the Triangle: ";
    cin >> base;
    setBase(base);
    cout << "Enter the height of the Triangle: ";
    cin >> height;
    setHeight(height);
}

//////////////////////////////////////////////////////////////////////////


#ifndef SQUARE_H
#define SQUARE_H
//#include "Shape.h"

class Square : public Shape {
    public:
        Square(int id, double l=0) : id(id), length(l) {}

        const char *shapeType() const { return "Square"; }
        void setProperties();
        double getArea() const { return length * length; }
        int shapeID() const { return id; }

        double getLength() const { return length; }
        void setLength(double l) { length = l; }
    private:
        int id;
        double length;
};

#endif // SQUARE_H 

//////////////////////////////////////////////////////////////////////////

//#include "Square.h"
#include <iostream>
using namespace std;

void Square::setProperties(){
    double length;
    cout << "Enter the side length of the square: ";
    cin >> length;
    setLength(length);
}

//////////////////////////////////////////////////////////////////////////

//#include "Shape.h"
//#include "Triangle.h"
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n = 0;
    vector<Shape*> shapes;
    shapes.push_back(new Triangle(++n));
    shapes.push_back(new Square(++n));

    while (true) {
        cout << "\nWelcome to the area calculator, please select a "
                "shape to work with below, or press 0 to exit\n";
        for (size_t i = 0; i < shapes.size(); i++)
            cout << shapes[i]->shapeID() << ": "
                 << shapes[i]->shapeType() << endl;

        int choice;
        cin >> choice;
        if (choice == 0)
            break;

        --choice;
        shapes[choice]->setProperties();
        cout << "the area of the " << shapes[choice]->shapeType()
             << " is: " << shapes[choice]->getArea() << endl;

    }

    return 0;
}

Last edited on
So, i'm getting an error: expected type-specifier before 'Square' when I try to build and run it. in int main()
Scratch that. Forgot to include square.h in main.

Sam
Thank everyone who helped with this very much. I had tried some of these methods to an extent, but didn't understand the information i was sourcing enough to find a way to make it work.

Seeing the different examples really helped me understand what I was doing wrong, and how to get it working.

Thanks again,
Sam
Topic archived. No new replies allowed.