Trying to print elements of an array of derived classes

In main.cpp, when it gets to void printShapesInArray(...), the print functiion of the corresponding shape in the array doesn't get called, I believe.

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
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include <iostream>
#include <string>
#include <array>
#include "Shapes.h"
#include "Circle.h"
#include "Rectangle.h"
#include "Square.h"

using namespace std;

string showMenu();
bool checkIfValidInput(int);
string shapeType(int);
void createCircle(double[]);
void createSquare(double[]);
void createRectangle(double[]);
void altMenu(Shapes[], int);
void printShapesInArray(Shapes[], int);

int main()
{
	string shapeType;
	int arraySize;
	double circVals[3];
	double sqVals [1];
	double rectVals[2];
	Shapes* shapesArr;

	cout << " Welcome!!\nHow many shapes would you like to create?   ";
	cin >> arraySize;
	cout << "\n\n";
	shapesArr = new Shapes[arraySize];

	for (int i = 0; i < arraySize; i++)
	{
		shapeType = showMenu();

		if (shapeType == "sq")
		{
			createSquare(sqVals);
			shapesArr[i] = Square(sqVals[0]);
		}
		else
		{
			if (shapeType == "re")
			{
				createRectangle(rectVals);
				shapesArr[i] = Rectangle(rectVals[0], rectVals[1]);
			}
			else
			{
				if (shapeType == "ci")
				{
					createCircle(circVals);
					shapesArr[i] = Circle(circVals[0], circVals[1], circVals[2]);
				}
			}
		}
	}
	
	altMenu(shapesArr, arraySize);


	system("pause");
	return 0;
}

string showMenu()
{
	int selection;
	bool repeat = false;

	do
	{
		cout << "Which shape would you like to create?" << endl;
		cout << "1. Square" << endl;
		cout << "2. Rectangle" << endl;
		cout << "3. Circle" << endl;
		cout << "4. Exit" << endl;
		cout << "Enter the number of your selection: ";
		cin >> selection;

		if (checkIfValidInput(selection))
		{
			return shapeType(selection);
		}
		else
		{
			repeat = true;
			cout << "\n\n";
		}
	}
	while(repeat);

	return "ex";
}

bool checkIfValidInput(int x)
{
	if(x <= 4)
	{
		return true;
	}

	cout << "\nWrong input!!!\nPlease enter a number on the menu." << endl;
	return false;
}

string shapeType(int x)
{
	if (x == 1)
	{
		return "sq";
	}
	else
	{
		if (x == 2)
		{
			return "re";
		}
		else
		{
			if (x == 3)
			{
				return "ci";
			}
		}
	}

	return "ex";
}

void createCircle(double userVals[])
{
	cout << "Input the points for the center of the circle." << endl;
	cout << "X: ";
	cin >> userVals[0];
	cout << "\n";
	cout << "Y: ";
	cin >> userVals[1];
	cout << "\n";
	cout << "Input the radius of the circle." << endl;
	cout << "Radius: ";
	cin >> userVals[2];
	cout << "\n\n";
}

void createSquare(double userVals[])
{
	cout << "Input a side length of the circle." << endl;
	cout << "Side: ";
	cin >> userVals[0];
	cout << "\n\n";
}

void createRectangle(double userVals[])
{
	cout << "Input the length of the rectangle." << endl;
	cout << "Length: ";
	cin >> userVals[0];
	cout << "\n";
	cout << "Width: ";
	cin >> userVals[1];
	cout << "\n\n";
}

void altMenu(Shapes sArr[], int size)
{
	int selection;

	cout << "What would you like to do?" << endl;
	cout << "1. Print all created shapes" << endl;
	cout << "2. Find area of a created shape" << endl;
	cout << "Enter the number of your selection: ";
	cin >> selection;

	if (selection == 1)
	{
		printShapesInArray(sArr, size);
	}
}

void printShapesInArray(Shapes sArr[], int size)
{
	Shapes temp[1];

	for (int i = 0; i < size; i++)
	{
		sArr[i].print(i);
	}
}


Shapes.h
1
2
3
4
5
6
7
8
9
10
#pragma once

class Shapes
{
	public:
		Shapes();
		double virtual area();
		void virtual print(int);
		~Shapes();	
};


Circle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once
#include "Shapes.h"

class Circle :	public Shapes
{
	private:
		double x;
		double y;
		double radius;
		double const PI = 3.14159265358979323846264338327950288419716939937510582097;

	public:
		Circle();
		Circle(int, int, double);
		void setX(double);
		void setY(double);
		void setRadius(double);
		double area();
		double getX();
		double getY();
		double getRadius();
		void print(int);
		~Circle();		
};


Square.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include "Shapes.h"

class Square :	public Shapes
{
	private:
		double side;

	public:
		Square();
		Square(double);
		void setSide(double);
		double area();
		double getSide();
		void print(int);
		~Square();		
};


Rectangle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include "Shapes.h"

class Square :	public Shapes
{
	private:
		double side;

	public:
		Square();
		Square(double);
		void setSide(double);
		double area();
		double getSide();
		void print(int);
		~Square();		
};


Here is the print(...) functions in each derived class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Shapes::print(int i)
{
}

void Circle::print(int i)
{
	cout << "Shape " << (i + 1) << "\nCircle" << endl;
	cout << "Center: (" << x << ", " << y << ")" << endl;
	cout << "Radius: " << radius << endl;
}

void Rectangle::print(int i)
{
	cout << "Shape " << (i + 1) << "\nRectangle" << endl;
	cout << "Length: " << length << endl;
	cout << "Width: " << width << endl;
}

void Square::print(int i)
{
	cout << "Shape " << (i + 1) << "\nSquare" << endl;
	cout << "Sides: " << side << endl;
}
Dynamic polymorphism in C++ has to be accessed through a reference or a pointer.

Your issue is that your shapesArr is just an array of Shapes objects. Not pointers.

When you do shapesArr[i] = Square(sqVals[0]); you're actually slicing your Square object to fit inside a Shapes object. This should usually be avoided by using references, but you can't have an array of references, so you have to have an array of pointers (or some other wrapper). Make it be an array of pointers instead (or unique_ptr so you don't have to deal with memory management).
1
2
3
4
5
6
7
8
9
10
11
12
13
Shapes** shapesArr;
// ...
shapesArr = new Shapes*[arraySize];
// ...
shapesArr[i] = new Square(sqVals[0]);

// ...

for (int i = 0; i < size; i++)
{
    delete shapesArr[i];
}
delete[] shapesArr;


Be sure to delete what you new.

Also, your base class destructor should be virtual, otherwise it's technically undefined behavior.


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
// Example program
#include <iostream>

class Shape {
  public:
    virtual void print()
    {
        std::cout << "I'm a generic shape!\n";   
    }
    
    virtual ~Shape() { }
};

class Square : public Shape {
    
    void print() override
    {
        std::cout << "I'm a Square!\n";   
    }
};

class Circle : public Shape {
    
    void print() override
    {
        std::cout << "I'm a Circle!\n";   
    }
};


int main()
{
    int num_shapes = 5;
    Shape** shapes = new Shape*[num_shapes];
    
    // setup
    for (int i = 0; i < num_shapes; i++)
    {
        if (i % 2 == 0) // if even
        {
            shapes[i] = new Square();
        }
        else
        {
            shapes[i] = new Circle();   
        }
    }
    
    // main logic
    for (int i = 0; i < num_shapes; i++)
    {
        shapes[i]->print();
    }
    
    
    // clean up dynamic resources
    for (int i = 0; i < num_shapes; i++)
    {
        delete shapes[i];
    }
    delete[] shapes;
}

I'm a Square!
I'm a Circle!
I'm a Square!
I'm a Circle!
I'm a Square!
Last edited on
OK, as per you suggestions, I edited my main and the corresponding header 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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <iostream>
#include <string>
#include <array>
#include "Shapes.h"
#include "Circle.h"
#include "Rectangle.h"
#include "Square.h"

using namespace std;

string showMenu();
bool checkIfValidInput(int);
string shapeType(int);
void createCircle(double[]);
void createSquare(double[]);
void createRectangle(double[]);
void altMenu(Shapes[], int);
void printShapesInArray(Shapes[], int);

int main()
{
	string shapeType;
	int arraySize;
	double circVals[3];
	double sqVals [1];
	double rectVals[2];
	Shapes** shapesArr;

	cout << " Welcome!!\nHow many shapes would you like to create?   ";
	cin >> arraySize;
	cout << "\n\n";
	shapesArr = new Shapes*[arraySize];

	for (int i = 0; i < arraySize; i++)
	{
		shapeType = showMenu();

		if (shapeType == "sq")
		{
			createSquare(sqVals);
			shapesArr[i] = new Square(sqVals[0]);
		}
		else
		{
			if (shapeType == "re")
			{
				createRectangle(rectVals);
				shapesArr[i] = new Rectangle(rectVals[0], rectVals[1]);
			}
			else
			{
				if (shapeType == "ci")
				{
					createCircle(circVals);
					shapesArr[i] = new Circle(circVals[0], circVals[1], circVals[2]);
				}
			}
		}
	}
	
	altMenu(*shapesArr, arraySize);

	for (int i = 0; i < arraySize; i++)
	{
		delete shapesArr[i];
	}
	delete[] shapesArr;

	system("pause");
	return 0;
}

string showMenu()
{
	int selection;
	bool repeat = false;

	do
	{
		cout << "Which shape would you like to create?" << endl;
		cout << "1. Square" << endl;
		cout << "2. Rectangle" << endl;
		cout << "3. Circle" << endl;
		cout << "4. Exit" << endl;
		cout << "Enter the number of your selection: ";
		cin >> selection;

		if (checkIfValidInput(selection))
		{
			return shapeType(selection);
		}
		else
		{
			repeat = true;
			cout << "\n\n";
		}
	}
	while(repeat);

	return "ex";
}

bool checkIfValidInput(int x)
{
	if(x <= 4)
	{
		return true;
	}

	cout << "\nWrong input!!!\nPlease enter a number on the menu." << endl;
	return false;
}

string shapeType(int x)
{
	if (x == 1)
	{
		return "sq";
	}
	else
	{
		if (x == 2)
		{
			return "re";
		}
		else
		{
			if (x == 3)
			{
				return "ci";
			}
		}
	}

	return "ex";
}

void createCircle(double userVals[])
{
	cout << "Input the points for the center of the circle." << endl;
	cout << "X: ";
	cin >> userVals[0];
	cout << "\n";
	cout << "Y: ";
	cin >> userVals[1];
	cout << "\n";
	cout << "Input the radius of the circle." << endl;
	cout << "Radius: ";
	cin >> userVals[2];
	cout << "\n\n";
}

void createSquare(double userVals[])
{
	cout << "Input a side length of the circle." << endl;
	cout << "Side: ";
	cin >> userVals[0];
	cout << "\n\n";
}

void createRectangle(double userVals[])
{
	cout << "Input the length of the rectangle." << endl;
	cout << "Length: ";
	cin >> userVals[0];
	cout << "\n";
	cout << "Width: ";
	cin >> userVals[1];
	cout << "\n\n";
}

void altMenu(Shapes sArr[], int size)
{
	int selection;

	cout << "What would you like to do?" << endl;
	cout << "1. Print all created shapes" << endl;
	cout << "2. Find area of a created shape" << endl;
	cout << "Enter the number of your selection: ";
	cin >> selection;

	if (selection == 1)
	{
		printShapesInArray(sArr, size);
	}
}

void printShapesInArray(Shapes sArr[], int size)
{
	Shapes temp[1];

	for (int i = 0; i < size; i++)
	{
		sArr[i].print(i);
	}
}


It now accesses the correct print functions, well, it prints the info from the first index, but in the next index/indices, the compiler throws this:

sArr[i].print(i);

Exception thrown: read access violation.
sArr->**** was 0xCDCDCDCD. occurred

I hope I edited it according to what you told me

(also unrelated, is there a better way to pause instead of utilizing system("pause")?)
Last edited on
You're no longer dealing with an array of "Shapes" objects, you're dealing with an array of Shapes pointers (Shapes*). So the places where you pass in a "Shapes sArr[]" is misleading, because you're currently passing in a single object, not an array.

Make the signature of the function be, for example,
altMenu(Shapes** sArr, int size)
or equivalently,
altMenu(Shapes* sArr[], int size)

Then, you do
1
2
3
4
	for (int i = 0; i < size; i++)
	{
		sArr[i]->print(i);
	}


And on line 61, don't dereference shapesArr.

Also, get rid of line 190, you never use a temp object so why have it?

(also unrelated, is there a better way to pause instead of utilizing system("pause")?)
There's a thread that discusses a bunch of stuff about pausing here: http://www.cplusplus.com/forum/beginner/1988/
I suggest reading it. One solution would be to run the program inside of cmd instead of through visual studio, or, if possible, configure visual studio to pause automatically, without having to use system.
Last edited on
Also, get rid of line 190, you never use a temp object so why have it?

I tried something before that turned out be redundant and forgot to remove that line along with the rest


In the two functions where I pass Shapes sArr[], I changed to Shapes** sArr. void altMenu(Shapes** sArr, int size) and void printShapesInArray(Shapes** sArr, int size). I changed the . to -> as well.


But know, I get a few warnings and errors.

altMenu(shapesArr, arraySize);
Warning C6001 Using uninitialized memory 'shapesArr'.

1
2
3
4
if (selection == 1)
	{
		printShapesInArray(sArr, size);
	}

Error C2664 'void printShapesInArray(Shapes [],int)': cannot convert argument 1 from 'Shapes **' to 'Shapes []'

altMenu(shapesArr, arraySize);
Error C2664 'void altMenu(Shapes [],int)': cannot convert argument 1 from 'Shapes **' to 'Shapes []'

shapesArr[i] = new Circle(circVals[0], circVals[1], circVals[2]);
Warning C4244 'argument': conversion from 'double' to 'int', possible loss of data
This warning is intentional. Is there a way to remove the warning or just ignore it and leave it?


There's a thread that discusses a bunch of stuff about pausing here: http://www.cplusplus.com/forum/beginner/1988/
I suggest reading it. One solution would be to run the program inside of cmd instead of through visual studio, or, if possible, configure visual studio to pause automatically, without having to use system.

Thanks for the reference
Last edited on
> altMenu(shapesArr, arraySize);
> Warning C6001 Using uninitialized memory 'shapesArr'.
weird, you initialise it on line 32
show your updated code

> cannot convert argument 1 from 'Shapes **' to 'Shapes []'
Ganado wrote:
You're no longer dealing with an array of "Shapes" objects, you're dealing with an array of Shapes pointers (Shapes*). So the places where you pass in a "Shapes sArr[]" is misleading, because you're currently passing in a single object, not an array.


> 'argument': conversion from 'double' to 'int', possible loss of data
> This warning is intentional. Is there a way to remove the warning or just ignore it and leave it?
¿why is it intentional?
Topic archived. No new replies allowed.