Inheritance and Member Function Overloading

Hey Guys,

So, just for full disclosure, here is the full question I am working on:
a. Start with a Point class to hold x and y values of a point. Overload
the >> operator to print point values and the + and – operators
to add and subtract point coordinates (hint: keep x and y separate
In the calculation). (Completed)

b. Create a base class Shape which will form the basis of your shapes.
The Shape class will contain functions to calculate area and
circumference of the shape, plus provide the coordinates (Points) of
a rectangle that encloses the shape (a bounding box). These will be
overloaded by the derived classes as necessary. Create a display()
function that will display the name of the class plus all stored
information about the class (including area, circumference, and
bounding box).

c. Build the hierarchy by creating the Shape classes Circle, Square,
and Triangle. For these derived classes, create default
constructors and constructors whose arguments can initialize the
shapes appropriately using the correct number of Point objects
(i.e., Circle requires a Point center and a radius; Square requires
four Point vertices, while Triangle requires three Point vertices).

d. In main(), create one instance each of the following: a Circle with a
radius of 23, a Square with sides 25, and a Triangle with sides 10,
20, 30. Define all of them so that the origin (0,0) is somewhere
within each object. Display the information from each object.

I completed part a, with help of course, and it seems to be working well. For part b, I am trying to figure out where I overload the functions? Do I over load the functions (area, circumference, etc.) in the base class (part b), or do I overload the functions in the derived classes (part c, which is not included yet)?

Here is my code thus far:
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
#include <iostream>
#include <cmath>
using namespace std;

#define PI 3.14159

//Part A

class Point {
	int x;
	int y;
	
	public:
		Point(int px , int py) : x(px) , y(py){}
		
		friend ostream &operator<<(ostream &stream, Point &p);
	 	Point operator+(const Point& pt);
	 	Point operator-(const Point& pt);
};

// >> Operator Overload  Works
ostream &operator<<(ostream &stream, Point &p) {
	stream << "(" << p.x << ", " << p.y << ")" << endl;
	return stream;
}

// + Operator Overload   Works   
Point Point::operator+(const Point& pt) {
	Point result = *this;
	result.x += pt.x;
	result.y += pt.y;
	return result;
}


// - Operator Overload  Works
Point Point::operator-(const Point& pt) {
	Point result = *this;
	result.x -= pt.x;
	result.y -= pt.y;
	return result;
 }

 
// Part B
 class Shape {
 	public:
		void area(int radius);
		void area(int length, int breadth);
		void area(double height, double breadth);
		
		void circumference(int radius);
		void circumference(int length, int breadth);
		void circumference(double height, double breadth);
		
		void boundbox(int radius);
		void boundbox(int length, int breadth);
		void boundbox(double height, double breadth);
		
		void display();
};


// Part D 	
int main() {
	Point pt0(0, 0); // Point Center
	Point pt1(0, 23); // Radius
	Point pt2(14, 14); // Top Right Corner
	Point pt3(14, -11); // Bottom Right Corner
	Point pt4(-11, 14); // Top Left Corner
	Point pt5(-11, -11); // Bottom Left Corner
	//Point pt6(,); // Top Vertex, TBD
	//Point pt7(,); // Bottom Left Vertex, TBD
	//Point pt8(,); // Bottom Right Vertex, TBD

// 	Circle cobject(pt0, pt1);
// 	cobject.display();
// 	
// 	Square sobject(pt2, pt3, pt4, pt5); //side length of 25
// 	sobject.display();
// 	
// 	Triangle tobject(pt6, pt7, pt8); //side length of 10, 20 30
// 	tobject.display();
	return 0;
}


I am pretty new to programming, so any suggestions would be greatly appreciated. Please point out any other places where I could improve my code!
In the derived classes, but you need to make the methods that you want overridden able to be overridden. This is done by prefixing the keyword virtual to a class prototype. virtual allows derived classes to override the base method. If the derived class does not override the base, then the compiler will just use functions from the base class.

Also, if you want to force a method to be overridden by the derived class, you can put the suffix = 0; at the end of a prototype. This requires that the derived class must implement the method, because the base class does not have any implementation.

Explanation of virtual:
http://stackoverflow.com/questions/2391679/can-someone-explain-c-virtual-methods/2391781#2391781

Edit: Just noticed how your Shape class has three different area and circumference functions. Your Shape class only needs one of each.
1
2
3
4
5
6
7
8
9
10
class Shape
{
public:
    virtual double area() = 0;
    virtual double circumference() = 0; //I would probably call this perimeter personally, and
             //just have an extra method in the derived Circle class called circumference.
    virtual ? boundbox() = 0; //the question mark needs to be a list of Points, typically
             //I use std::vector to hold lists.  So I would put std::vector<Point>
    virtual void display() = 0;
};

The Shape class in my example is an example of an interface, since all the methods are purely virtual. This means any derived class would be required to implement these methods like I was saying earlier.
Last edited on
Hey kevinkjt2000

So I tried to implement what you suggested (I took out all the other junk in there, so now I am only working with a circle class right now, and only working on the area function. I figure, once I get that, its pretty easy to extrapolate to the other functions and classes) Took a bit of stuggling, but I think I got it. Please correct me if I'm wrong.
I did have trouble though in part c. I tried adding a new variable, trying to get a distance value from p0 to p1 (the radius magnitude), but I can't convert from a point to a double. This may be pretty trivial, but I can't seem to figure it out. Any suggestions?

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
#include <iostream>
#include <cmath>
using namespace std;

#define PI 3.14159

//Part A

class Point {
	int x;
	int y;
	
	public:
		Point(int px , int py) : x(px) , y(py){}
		
		friend ostream &operator<<(ostream &stream, Point &p);
	 	Point operator+(const Point& pt);
	 	Point operator-(const Point& pt);
};

// >> Operator Overload
ostream &operator<<(ostream &stream, Point &p) {
	stream << "(" << p.x << ", " << p.y << ")" << endl;
	return stream;
}

// + Operator Overload
Point Point::operator+(const Point& pt) {
	Point result = *this;
	result.x += pt.x;
	result.y += pt.y;
	return result;
}


// - Operator Overload
Point Point::operator-(const Point& pt) {
	Point result = *this;
	result.x -= pt.x;
	result.y -= pt.y;
	return result;
 }

 
// Part B
 class Shape {
 	public:
		virtual double area() = 0;
		//virtual int circumference() = 0;
		//virtual ? boundbox() = 0;        // vector?
		//virtual void display() = 0;
};


// //Part C
 class Circle: public Shape {
 		Point s0, s1;
		public:
 		Circle(); 															//Default Constructor
 		Circle (const Point &pt0, const Point &pt1): s0(pt0), s1(pt1) {}		//Constructor with point center and radius arguments
		double area(){
			Point radius = s1 - s0;
			void distrad(radius) = sqrt((p.x * p.x) + (p.y*p.y));
			double area_c = PI * distrad * distrad;
			cout << "Area: " << area_c << endl;
		}
 };
 

// Part D 	
int main() {
	Point pt0(0, 0); // Point Center
	Point pt1(0, 23); // Radius

	Circle cobject(pt0, pt1);
	cobject.area();

	return 0;
}


Errors:

overload2.cpp: In member function ‘virtual double Circle::area()’:
overload2.cpp:63:23: error: variable or field ‘distrad’ declared void
void distrad(radius) = sqrt((p.x * p.x) + (p.y*p.y));
^
overload2.cpp:64:25: error: ‘distrad’ was not declared in this scope
double area_c = PI * distrad * distrad;
^
On line 63 you tried to declare a void variable.
Try declaring a double variable instead and get rid of (radius) and calculate the distance from the subtracted point you made on line 62.
double distrad = sqrt((radius.x * radius.x) + (radius.y * radius.y));
Then do not forget you are writing an area function that returns a double, so you should return area_c; at the end of the function. I would recommend not printing to the screen inside the area function, but do the printing wherever you call the area function from by using the returned value.
But, by using radius.x and radius.y, both my x and y are private members of my point class, therefore giving me errors
Here is something similar to what he is looking for. I did a few things different to make it faster to code such as origin instead of entering each point and used used sides/lengths instead of points for bounding box.

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
#include <iostream>
#include <cmath> //sqrt
#include <vector> //std::vector

//You can use double instead of float if you want it to be more accurate
//but for these I don't think they really need to be more than a few
//digits
struct Point //this will be a basic point without operators
{
    float x , y;
};

struct BoundingBox
{
    float top , left , width , height;
};

class Shape
{
    public:
    	virtual ~Shape(){}
        virtual float area( void ) const = 0;
        virtual float perimeter( void ) const = 0; //circumference for circles but oh well
    protected:
    	Point _origin;
	 	BoundingBox bounds;
};

//if you have a square derive from rectangle
//you might want to use virtual publics or consider
//composition instead of inheritance hierarchy 

class Square : public Shape
{
    public:
        Square( const float width , const Point origin );
        float area( void ) const;
        float perimeter( void ) const;
    private:
        float width;
};

Square::Square( const float width , const Point origin ) : width( width )
{
	_origin = origin;
	bounds.left = origin.x - width / 2.0f;
	bounds.top = origin.y - width / 2.0f;
	bounds.width = width;
	bounds.height = width;
}

float Square::area( void ) const
{
	return width * width;
}

float Square::perimeter( void ) const
{
	const int sides = 4;
	return sides * width; 
}


class Circle : public Shape
{
    public:
        Circle( const float radius , const Point origin );
        float area( void ) const;
        float perimeter( void ) const; //yeah its circum but in my example its perim
    private:
        float radius;
};

Circle::Circle( const float radius , const Point origin ) : radius( radius )
{
	_origin = origin;
	bounds.left = origin.x - radius;
	bounds.top = origin.y + radius;
	bounds.width = radius * 2; //radius * 2 = diameter
	bounds.height = bounds.width; //height and width are same in a circle
}

float Circle::area( void ) const
{
	const float pi = 3.14159f;
	return pi * radius * radius;
}

float Circle::perimeter( void ) const
{
	const float pi = 3.14159;
	return 2 * pi * radius;
}

//mine is a Equilateral Triangle
class Triangle : public Shape
{
	public:
		Triangle( const float length , const Point origin );
		float area( void ) const;
		float perimeter( void ) const;
	private:
		float length;	
};

Triangle::Triangle( const float length , const Point origin ) : length( length )
{
	_origin = origin;
	bounds.left = origin.x - length / 2.0f;
	bounds.top = origin.y - length / 2.0f;
	bounds.width = length;
	bounds.height = sqrt( length * length - length / 2.0f * length / 2.0f );
}

float Triangle::area( void ) const
{
	return length * bounds.height / 2.0f;
}

float Triangle::perimeter( void ) const
{
	const int sides = 3;
	return sides * length;
}

int main()
{
	Point origin{ 10 , 5 }; //center of shape is at 10 , 5
	
	std::vector<Shape *> shapes; //smart pointer would be better
	
	shapes.push_back( new Triangle(10,origin) );
	shapes.push_back( new Circle(5,origin) );
	shapes.push_back( new Square(10,origin) );
	
	for( const auto &it : shapes )
	{
		//triangle , circle , square
		std::cout << "Area: " << it->area() << " Perimeter: " << it->perimeter() << std::endl;
		delete it;
	}
		
	return 0;
}
Area: 43.3013 Perimeter: 30
Area: 78.5397 Perimeter: 31.4159
Area: 100 Perimeter: 40



http://ideone.com/rQ7Uj7

*small fix
Last edited on
Hey giblet!
I just tried running that code, but got quite a few errors?

ideone.cpp: In function ‘int main()’:
ideone.cpp:128:8: warning: extended initializer lists only available with -std=c++11 or -std=gnu++11 [enabled by default]
Point origin{ 10 , 5 }; //center of shape is at 10 , 5
^
ideone.cpp:136:19: error: ISO C++ forbids declaration of ‘it’ with no type [-fpermissive]
for( const auto &it : shapes )
^
ideone.cpp:136:24: error: range-based ‘for’ loops are not allowed in C++98 mode
for( const auto &it : shapes )
^
ideone.cpp:139:30: error: base operand of ‘->’ is not a pointer
std::cout << "Area: " << it->area() << " Perimeter: " << it->perimeter() << std::endl;
^
ideone.cpp:139:62: error: base operand of ‘->’ is not a pointer
std::cout << "Area: " << it->area() << " Perimeter: " << it->perimeter() << std::endl;
^
ideone.cpp:140:10: error: type ‘const int’ argument given to ‘delete’, expected pointer
delete it;
You don't have c++11 enabled as the first one says.
warning: extended initializer lists only available with -std=c++11 or -std=gnu++11 [enabled by default]


Try compiling with
-std=c++11
enabled.

The older version you would have to do a few fixes:

1
2
3
4
5
6
7
8
9
10
11
Point origin{ 10 , 5 };
Point origin;
origin.x = 10;
origin.y = 5;

for( const auto &it : shapes )
for( std::vector<Shape *>::const_iterator it = shapes.cbegin(); it != shapes.cend(); ++it )
{
    std::cout << "Area: " << *it->area() << " Perimeter: " << *it->perimeter() << std::endl;
    delete *it;
}


Also I was just trying to show you a way to use the derived classes so you could have something to look at while creating yours. To test the code I provided you can click on the link posted.

http://ideone.com/rQ7Uj7
and it will compile there.
Last edited on
Hey guys,
So I was pleased to see that I have no more errors! YAYYY
I was a little displeased with the magnitude of my area and circumference...
Obviously something isn't going right. Any suggestions?

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
#include <iostream>
#include <cmath>
using namespace std;

#define PI 3.14159

//Part A

class Point {	
	public:
		int x;
		int y;
		Point(int px , int py) : x(px) , y(py){}
		
		friend ostream &operator<<(ostream &stream, Point &p);
	 	Point operator+(const Point& pt);
	 	Point operator-(const Point& pt);
};

// >> Operator Overload
ostream &operator<<(ostream &stream, Point &p) {
	stream << "(" << p.x << ", " << p.y << ")" << endl;
	return stream;
}

// + Operator Overload
Point Point::operator+(const Point& pt) {
	Point result = *this;
	result.x += pt.x;
	result.y += pt.y;
	return result;
}


// - Operator Overload
Point Point::operator-(const Point& pt) {
	Point result = *this;
	result.x -= pt.x;
	result.y -= pt.y;
	return result;
 }

 
// Part B
 class Shape {
 	public:
		virtual double area() = 0;
		virtual double circumference() = 0;
		//virtual ? boundbox() = 0;        // vector?
		virtual void display() = 0;
};


// //Part C
 class Circle: public Shape {
 		Point s0, s1;
		public:
 			double distrad, area_c, circum_c;
			Circle(); 				//Default Constructor
 			Circle (const Point &pt0, const Point &pt1): s0(pt0), s1(pt1) {}		//Constructor with point center and radius arguments
			
 			double area();
			double circumference();
			//void boundbox
			void display();
 };

double Circle::area(){
	Point radius = s1 - s0;
	distrad = sqrt((radius.x * radius.x) + (radius.y * radius.y));
	double area_c = PI * distrad * distrad;
	return area_c;
}

double Circle::circumference(){
	double circum_c = PI * 2 * distrad;
	return circum_c;
}
 
void Circle::display(){
	cout << "Class"	<< endl;
	cout << "Area: " << area_c << endl;
	cout << "Circumference: " << circum_c << endl;
	//cout << "Boundbox: " <<  << endl;                     //Haven't defined this yet
}

// Part D 	
int main() {
	Point pt0(0, 0); // Point Center
	Point pt1(0, 23); // Radius
	Point pt2(14, 14); // Top Right Corner
	Point pt3(14, -11); // Bottom Right Corner
	Point pt4(-11, 14); // Top Left Corner
	Point pt5(-11, -11); // Bottom Left Corner
	Point pt6(-3, 19); // Top Vertex, TBD
	Point pt7(-3, -1); // Bottom Left Vertex, TBD
	Point pt8(7, -1); // Bottom Right Vertex, TBD

	Circle cobject(pt0, pt1);
	cobject.display();
}



Class
Area: 3.18441e-314
Circumference: 1.12244e-317
I am a bit confused as to the radius being a point? The radius should be the center of the circle to any edge. To create a circle you are going to need 2 points then you can get infinite amount of points if needed. The two required are the origin point(center) and one edge. The radius will be the distance from the center to the radius.

To find the distance you can use the distance formula: [output]d = sqrt( ( edge.x - origin.x )2 + ( edge.y - origin.y)2 )

So for your example you have a center of (0,0) and an edge at (0,23) according to line 99. Circle cobject(pt0, pt1);


So the radius of this will be 23. Reason: (well besides the obvious)
radius = sqrt( (0-0)2 + (23-0)2 ) = sqrt( 02 + 232 ) = sqrt( 0 + 529 ) = sqrt( 529 ) = 23

Though the obvious way would be to notice that the x are the same and the y changes by 23 so it must be 23.

Why do you have: double distrad, area_c, circum_c;


Anyways the assignment says
Circle requires a Point center and a radius


So the constructor should look like:

Circle( const Point &Center , const double &Radius );

or something along the lines of that.

It will then make it much easier for finding the area and perim.

You can simply do:

1
2
3
4
5
double area( void ) const
{
    const double pi = 3.14159;
    return pi * radius * radius;
}


I was trying to make the radius a point, and figure out a way to get the distance, that way, following that logic, it would be easier to create the triangle and the square, because they involve the process of given several points, get the distance between to adjacent points. So it was just me trying to get a generic scheme
I put double distrad, area_c and circum_c; in there to be able to return a variable, and use them in my print statements. Why they are defined under public, is because my compiler yelled at me until I put them in a place within the scope.
I tried implementing the constructor as you suggested, and making the area function as you did, but I just got back errors, such as radius is out of scope. So I publicly declared radius, and then it just gave me an error stating:

/tmp/cciJu4xe.o:overload2.cpp:(.text+0x35a): undefined reference to `Circle::Circle(Point const&, double const&)'
/tmp/cciJu4xe.o:overload2.cpp:(.text+0x35a): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Circle::Circle(Point const&, double const&)'
/usr/lib/gcc/x86_64-pc-cygwin/4.8.1/../../../../x86_64-pc-cygwin/bin/ld: /tmp/cciJu4xe.o: bad reloc address 0x0 in section `.pdata$_ZN5PointC1Eii'
collect2: error: ld returned 1 exit status

Here is my circle class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 class Circle: public Shape {
 		Point s0, s1;
		public:
 			double area_c, circum_c, radius;
			Circle(); 					//Default Constructor
			Circle(const Point &pt0, const double &radius);
 			double area();
			double circumference();
			void display();
 };

double Circle::area(){
	const double pi = 3.14159;
	double area_cg = pi * radius * radius;
	return area_cg;
}
undefined reference to `Circle::Circle(Point const&, double const&)'

Have you defined this constructor anywhere yet? This compile error should be fairly obvious.

One issue you may run into when defining the constructor is that you have double radius; declared in your Circle class and it has the same exact name as a parameter to you constructor.
Example on how to fix that:
1
2
3
4
5
Circle::Circle(Point const& center, double const& radius)
{
    this->radius = radius;
    this->center = center;
}

This this-> is a way to access members of the class instead of local variables such as the parameters that are passed in. Alternatively you could think of a different name for your parameter such as Radius with a capital R.

This example would also require the assignment operator (=) to be overridden in the Point class and Point center; to be added as a variable to the Circle class. The center point and the radius should be the only data variables for your Circle class, and I would assume that they need to be in the private section for this assignment.
Last edited on
Topic archived. No new replies allowed.