Reputation:
I am working on a project for understanding classes and have hit a wall. If you have any advice about my syntax, please let me know where I am going wrong as I am still quite new to programming, but my question is to do with class inheritance. (A, C and D are included but pretty well completed).
My project:
A. Start with a point class... Override << (print values), +, - (to add and subtract point coordinates). I feel I have completed this portion.
B. Create a base class Shape. Shape will contain functions to calculate area, circumference and take point values to create a box that encapsulates the given shape. These will be overloaded by derived classes. Create a display() function that displays all relevant info (name, area, circumference and encapsulating box.
C. Build a heirarchy for shapes by making circle, square, triangle... add default and custom constructors whos arguments initialize the shapes using the correct number of point objects. I feel I have satisfied this too.
D. In main() Create an instance of each. Circle radius = to 23, square sides each = 25, Triangle sides = 10, 20 and 30 (very flat triangle, area = 0). Define each to contain the origin (0, 0). Display all the info. I feel I have completed this (minus the display function).
My question is (and where I am struggling), "How do I properly make/access functions from a base class (shape) to return meaningful information."
Do I literally just make them all virtual since some classes dont have the same information as others? (like Area() and Circumference()?)
#include <iostream>
#include <cmath>
using namespace std;
class Point {
public:
int x, y;
Point() {
x = 0;
y = 0;
}
Point(int x, int y): x(x), y(y) {} // constructor
friend ostream& operator<<(ostream& out, const Point number) { //Involves ostream to output the numbers
out << "(" << number.x << ", " << number.y << ")"; //that were input into the x and y values of Point.
return out;
}
friend Point operator+(Point first, Point second) { //Takes two mathematical vectors and tells the compiler
Point add; // to add the x values together and the y values together
add.x = first.x + second.x;
add.y = first.y + second.y;
return add;
}
friend Point operator-(Point first, Point second) { // same as above but with subtraction.
Point subtract;
subtract.x = first.x - second.x;
subtract.y = first.y - second.y;
return subtract;
}
};
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
/*
int Display() {
//Do something..... Create a display function
return 0;
}
int BoundingBox() {
//Do something again......
return 0;
}
*/
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle(): Shape() {};
Circle (Point p1, float r) { //Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};
class Square: public Shape {
Point first, second, third, fourth;
public:
Square(): Shape() {};
Square(Point p1, Point p2, Point p3, Point p4) { // Takes four point arguments and initializes them
first = p1;
second = p2;
third = p3;
fourth = p4;
height = second.x - first.x; //calculates the height and width from points
width = third.y - first.y;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override{ // Calculates area by measuring the difference between given points
return(height * width);
}
virtual ~Square() {};
};
class Triangle: public Shape {
Point first, second, third;
public:
Triangle(): Shape() {};
Triangle(Point p1, Point p2, Point p3) { // Takes three point arguments and initializes them
first = p1;
second = p2;
third = p3;
height = third.y - first.y;// due to the nature of the question, this only works for flat triangles.
width = second.x - first.x;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override {
return ((height * width) / 2);
}
virtual ~Triangle() {};
};
int main() {
Point p1(0, 0), p2(25, 0), p3(0, 25), p4(25, 25), p5(20, 0), p6(30, 0);
Circle c1 (p1, 23); // Circle with origin (0, 0) and a radius of 23
Square s1 (p1, p2, p3, p4); // Square with 4 points and the origin
Triangle t1 (p1, p5, p6); // Extraordinarily flat triangle with origin
cout << c1.Circumference() << endl;
cout << s1.Area() << endl;
cout << t1.Area() << endl;
}
At this point, I am feeling a bit lost of the woods and I am sure I have either created several mistakes along the way, or just a few, but regardless, I don't understand. Any advice would be appreciated!
edit: I have updated my code to include the recommendations to include virtual deconstructors, remove the getheight etc... statements, and add virtual to the derived functions
Upvotes: 0
Views: 1563
Reputation: 170
When you're working with inheritance, make sure to use a virtual destructor in all of your inherited classes, as well as the base class.
Your inherited virtual functions would benefit from being marked virtual
and override
too, in case you want to make further specializations.
You are overriding inherited functions, but then they do the same thing as the original, e.g. GetHeight()
. That kinda defeats the point of inheriting those functions. They also do not need to be virtual if they aren't overridden.
Your derived classes would benefit from explicitly calling the base class's constructor. It will call the default constructor if you don't provide a specific constructor to call, which may or may not be the behaviour you intended - IMO it's safer to always provide the base class constructor you want!
As an example:
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle() : Shape() {};
Circle (Point p1, float r) : Shape() {
// Note you may wish to set the height and width here!
//Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};
Upvotes: 3