How to achieve Multilevel Inheritance with classes - c++

I am trying to do some multilevel inheritance from the Shape class to Rectangle, Circle and Triangle classes. From Rectangle I need to inherit a Square class and print the area, info, etc.. as well as Ellipse from Circle and Isosceles from Triangle. So far my first inherited classes work fine, but whenever I try to make the "grandchildren" class work I cannot make it work. I have no idea what I might be doing wrong. Here is the code:
#include <iostream>
using namespace std;
class Shape{
protected:
string name;
float area;
public:
Shape(string nm):name(nm){}
//Getters
string getName(){ return name; }
float getArea(){}
//Setters
virtual void setArea(){}
//Print
virtual void printInfo()
{
cout << "Name: " << name << " Color: " << endl;
}
};
class Rectangle : public Shape{
private:
float length, width;
public:
Rectangle(string nm, float l, float w):Shape::Shape(nm), length(l), width(w){}
Shape::getName();
//Setters
void setArea(){ area = length*width; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " L: " << length << " W: " << width << " A: " << area << endl;
}
};
class Square : public Rectangle{
private:
float length;
public:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm){}
float getLength(){return length;}
//Setters
void setArea(){ area = length *length; }
};
class Circle : public Shape{
private:
float radius;
const float pi = 3.0;
public:
Circle(string nm, float r):Shape::Shape(nm), radius(r){}
//Setters
void setArea(){ area = pi*radius*radius; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " R: " << radius << " A: " << area << endl;
}
};
//class Ellipse : public Circle{
//
//private:
// float length, width, radius1, radius2;
//
//public:
// Ellipse(string nm, int clr, float l, float w);
//
// //Setters
//void setArea(){ area = radius1 * radius2; }
//
//};
class Triangle : public Shape{
private:
float a, base, c, height;
public:
Triangle(string nm, float a, float b, float c, float h):Shape::Shape(nm), a(a), base(b), c(c), height(h){}
//Setters
void setArea(){ area = (base*height)/2; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " Color: " << " A: " << a << " Base: " << base << " C: " << c << " H: " << height << " P: " << " A: " << area << endl;
}
};
//class Isosceles : public Triangle{
//
//private:
// float base, height;
//
//public:
// Isosceles(string nm, int clr, float l, float w);
//
// //Setters
// void setArea(){ area = (base*height)/2; }
//
//};
int main() {
Rectangle r("Rectangle", 10, 20);
Circle c("Circle", 1);
Triangle tt("Triangle", 2, 2, 3, 3);
Square ss("Square", 10);
Shape* s;
Shape* t;
Shape* u;
Shape* v;
s = &r;
t = &c;
u = &tt;
v = &ss;
//Set and print area of Rectangle
s->setArea();
s->printInfo();
//Set and print area of Circle
t->setArea();
t->printInfo();
//Set and print area of Triangle
u->setArea();
u->printInfo();
//Set and print area of Rectangle
v->setArea();
v->printInfo();
return 0;
}
I get an error while setting up the Square class over here:
class Square : public Rectangle{
private:
float length;
public:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm){}
I commented out the Ellipse and Isosceles classes just so I could set up correctly Square and work no them later.
This is my first time asking something, so if something is not correct please let me know.
Thank you for your help.

In your Square class I believe I found one mistake...
Try doing the following with your square constructor:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm, l, l){}
As opposed to what you had... that will fix the errors you are getting with the Square class.
The reason for the difference is because when you were passing arguments to the Rectangle constructor from the Square constructor you were leaving some arguments unintialized (in the Rectangle constructor).

Related

C++ "'Shape': cannot instantiate abstract class" can't find the source of the problem

I have the class Shape that 5 different classes (in different files) inherit from it.
After overriding all the pure virtual functions in all the different classes I get this error:
'Shape': cannot instantiate abstract class and it won't tell me from where the error is.
This is the Shape class:
#pragma once
#include "Point.h"
#include "Canvas.h"
#include <string>
class Shape
{
public:
Shape(const std::string& name, const std::string& type);
virtual double getArea() const = 0;
virtual double getPerimeter() const = 0;
virtual void draw(const Canvas& canvas) = 0;
virtual void move(const Point& other) = 0; // add the Point to all the points of shape
void printDetails() const;
std::string getType() const;
std::string getName() const;
virtual void clearDraw(const Canvas& canvas) = 0;
protected:
std::string _name;
std::string _type;
};
and here is an example of 2 classes that inherit from Shape:
class Circle : public Shape
{
Point _center;
double _radius;
public:
Circle(const Point& center, double radius, const std::string& type, const std::string& name);
~Circle();
const Point& getCenter() const;
double getRadius() const;
virtual void draw(const Canvas& canvas);
virtual void clearDraw(const Canvas& canvas);
// override functions if need (virtual + pure virtual)
virtual void move(const Point& other);
virtual double getArea() const;
virtual double getPerimeter() const;
};
And I suspect the problem is coming from this class, and in this class, I'm keeping the functions pure virtual because from this class other classes inherit too and they need a different implementation:
#include "Shape.h"
#include "Point.h"
#include <vector>
class Polygon : public Shape
{
public:
Polygon(const std::string& type, const std::string& name);
virtual ~Polygon();
// override functions if need (virtual + pure virtual)
virtual void move(const Point& other);
virtual double getArea() const = 0;
virtual double getPerimeter() const = 0;
virtual void draw(const Canvas& canvas) = 0;
virtual void clearDraw(const Canvas& canvas) = 0;
protected:
std::vector<Point> _points;
};
Here is the part in the code where I think the error might occur:
if (optionChosen == 0) // Circle
{
double x = 0;
double y = 0;
double radius = 1.0;
std::string name;
std::cout << "Please enter X: " << std::endl;
std::cin >> x;
std::cout << "Please enter Y: " << std::endl;
std::cin >> y;
do
{
std::cout << "Please enter radius: " << std::endl;
std::cin >> radius;
if (radius < 1)
{
std::cout << "Invalid radius... Try again" << std::endl;
}
// If radius is invalid this code will run again
} while (radius < 1);
std::cout << "Enter the name of the shape: " << std::endl;
std::cin >> name;
const Point& center = Point(x, y);
// Create a new circle and push it to the vector
Circle circle = Circle::Circle(center, radius, "Circle", name); // Circle inherits from Shape
_shapes.push_back(circle);
}
else if (optionChosen == 1) // Arrow
{
double point1[2] = { 0 };
double point2[2] = { 0 };
std::string name;
std::cout << "Enter the X of point number: 1" << std::endl;
std::cin >> point1[0];
std::cout << "Enter the Y of point number: 1" << std::endl;
std::cin >> point1[1];
std::cout << "Enter the X of point number: 2" << std::endl;
std::cin >> point2[0];
std::cout << "Enter the Y of point number: 2" << std::endl;
std::cin >> point2[1];
std::cout << "Enter the name of the shape: " << std::endl;
std::cin >> name;
const Point& Point1 = Point(point1[0], point1[1]);
const Point& Point2 = Point(point2[0], point2[1]);
// Create a new arrow and push it to the vector
Arrow arrow = Arrow::Arrow(Point1, Point2, "Arrow", name); // Arrow inherits from polygon
_shapes.push_back(arrow);
}
else if (optionChosen == 2) // Triangle
{
double point1[2] = { 0 };
double point2[2] = { 0 };
double point3[2] = { 0 };
std::string name;
std::cout << "Enter the X of point number: 1" << std::endl;
std::cin >> point1[0];
std::cout << "Enter the Y of point number: 1" << std::endl;
std::cin >> point1[1];
std::cout << "Enter the X of point number: 2" << std::endl;
std::cin >> point2[0];
std::cout << "Enter the Y of point number: 2" << std::endl;
std::cin >> point2[1];
std::cout << "Enter the X of point number: 3" << std::endl;
std::cin >> point3[0];
std::cout << "Enter the Y of point number: 3" << std::endl;
std::cin >> point3[1];
std::cout << "Enter the name of the shape: " << std::endl;
std::cin >> name;
const Point& Point1 = Point(point1[0], point1[1]);
const Point& Point2 = Point(point2[0], point2[1]);
const Point& Point3 = Point(point3[0], point3[1]);
// Create a new triangle and push it to the vector
Triangle triangle = Triangle::Triangle(Point1, Point2, Point3, "Triangle", name); // Triangle inherits from Polygon
_shapes.push_back(triangle);
}
else if (optionChosen == 3) // Rectangle
{
double topLeftCorner[2] = { 0 };
double length = 0;
double width = 0;
std::string name;
std::cout << "Enter the X of the left corner: " << std::endl;
std::cin >> topLeftCorner[0];
std::cout << "Enter the Y of the left corner: " << std::endl;
std::cin >> topLeftCorner[1];
std::cout << "Please enter the length of the shape: " << std::endl;
std::cin >> length;
std::cout << "Please enter the width of the shape: " << std::endl;
std::cin >> width;
std::cout << "Enter the name of the shape: " << std::endl;
std::cin >> name;
const Point& point = Point(topLeftCorner[0], topLeftCorner[1]);
// Create a new rectangle and push it to the vector
myShapes::Rectangle rectangle = myShapes::Rectangle(point, length, width, "Rectangle", name); // Rectangle inherits from Polygon
_shapes.push_back(rectangle);
}
If someone could help me find the problem I would be very happy.
You cannot store the object Shape in a vector, since it contains a pure virtual function. You can store pointers in the vector instead, or smart pointers, and create the child classes appropriately.
std::vector<Shape*> _shapes;
//…
_shapes.push_back( new Circle( … ) );
or
std::vector<std::unique_ptr<Shape>> _shapes;
//…
_shapes.push_back( std::make_unique<Circle>( center, radius, "Circle", name ) );
Also, when using inheritance, I'd recommend using the override keyword. So in your Circle class, for example, you would have
void move(const Point& other) override;

Error: double free or corruption (out): 0x00007fffffffddf0 ***

I am playing around with hierarchical objects and pointers and have written a base class Circle, then two classes Cylinder and Sphere that both derive from Circle.
When I run the program I get the error: double free or corruption (out): 0x00007fffffffddf0 ***
So I tried running the code through GDB. I found that the error occurs when I call the Cylinder destructor, which calls the virtual destructor for Circle. However I don't understand why this is happening.
From my research it seems this kind of error occurs when the code tries to deallocate memory that is not available to it.
I thought perhaps the destructor for Cylinder was causing the problem, since it is called first, so I commented out all of the Sphere and Circle object lines in main() and just used the Cylinder code.
When the destructor for the Cylinder pointer was called it resulted in a Segmentation Fault, so I am trying to access memory out of range.
Now I'm thoroughly confused.
Here is my code:
#include <iostream>
#include <cmath> // used for square
static constexpr float PI = 3.14159;
using namespace std;
class Circle{
protected:
float radius;
public:
float getRadius(){
return radius;
}
void setRadius(float r){
radius = r;
}
float calcCircleArea(){
return PI * pow(radius, 2);
}
float calcCircumference(){
return 2 * PI * radius;
}
Circle(){
// default constructor
}
Circle(float rad){
radius = rad; // overloaded constructor
}
virtual ~Circle(){ // virtual destructor
cout << "Destroying Circle Constructor" << endl;
}
};
class Cylinder: public Circle{
private:
float height;
public:
float getHeight(){
return height;
}
void setHeight(float h){
height = h;
}
float calcVol(){
float circleArea = calcCircleArea();
float vol = circleArea * height;
}
float calcSurfaceArea(){
float circum = calcCircumference();
float circleArea = calcCircleArea();
float cylSurfArea = (circleArea *2) + (circum * height);
}
Cylinder(){} // default constructor
Cylinder(float r, float h){ // overloaded constructor
radius = r;
height = h;
}
~Cylinder(){ // destructor
cout << "Destroying Cylinder Constructor" <<endl;
}
};
class Sphere : public Circle {
public:
float calcSurfaceArea(){
float r = getRadius();
return 4* PI * pow(r,2);
}
float calcVol(){
float r = getRadius();
return (4.0/3.0) * PI * pow(r,3);
}
Sphere(){} // default constructor
Sphere(float r){
radius = r;
}
~Sphere(){ // destructor
cout << "Destroying Sphere Constructor" << endl;
}
};
int main(){
cout << "Enter radius of circle and height of cyl:" << endl;
float r;
float h;
cin >> r >> h;
Sphere s1(r);
Cylinder cyl1(r,h);
Circle cir1(r);
//****************************
// Set up pointers
//****************************
Circle *circPtr;
circPtr = &cir1;
Sphere *sPtr;
sPtr = &s1;
Cylinder *cylPtr;
cylPtr = &cyl1;
cout << "Sphere vol : " << sPtr->calcVol() << endl;
cout << "Sphere SA : " << sPtr->calcSurfaceArea() << endl;
cout << "Cyl vol : " << cylPtr->calcVol() << endl;
cout << "Cyl SA : " << cylPtr->calcSurfaceArea() << endl;
cout << "Circle area : " << circPtr->calcCircleArea() << endl;
cout << "Circle circum : " << circPtr->calcCircumference() << endl;
cout << "sphere RADIUS : " << sPtr->getRadius() << endl;
cout << "cyl pointer VOLUME : " << cylPtr->calcVol() << endl;
cout << "circ pointer AREA: " << circPtr->calcCircleArea() << endl;
delete cylPtr;
delete sPtr;
return 0;
}
You're allocating your cylinder and sphere on the stack, then calling delete on pointers to them. This will destroy your objects twice. Once when you call delete, and once when they go out of scope (main ends).
Don't call delete on objects that you didn't create with new. Especially don't call delete on the address of stack objects.

Accessing member functions through pointers

Why am I getting the address in the output. Rather I should get the Output Length= (value input by user) , Width = (value input by user).
As in the main body of program after getting input R1.getdata() , ptr->result() should display the result of Rectangle class.
#include <iostream>
using namespace std;
class Rectangle {
protected:
float length;
float width;
public:
void getdata() {
cout << "Enter length and width= ";
cin >> length >> width;
}
void result() {
cout << "Length = " << length << "\nWidth = " << width << endl;
}
};
class Area : public Rectangle {
private:
float area;
public:
void calc_area() { area = length * width; }
void result() { cout << "Area = " << area << endl; }
};
class Perimeter : public Rectangle {
private:
float perimeter;
public:
void calc_peri() { perimeter = 2 * (length + width); }
void result() { cout << "Perimeter = " << perimeter << endl; }
};
void main() {
Rectangle R1;
Area A1;
Perimeter P1;
Rectangle *ptr;
R1.getdata();
ptr = &A1;
ptr->result();
}
You are getting the wrong values, because you are calling ptr->result(); on a uninitialized Area object (A1), which has been upcasted from pointer to Rectangle object.
The values the user inputs though are used in the R1 object, which you then don't use anymore. Moreover, you should make the result() method virtual.
Lastly, the syntax for calling base class method on a pointer to an inheriting class is: ptr->Rectangle::result();.
Below you will find your code with some fixes that demonstrate things I wrote about:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Rectangle {
protected:
float length;
float width;
public:
void getdata() {
cout << "Enter length and width= ";
cin >> length >> width;
std::cout << length << " " << width << std::endl;
}
virtual void result() {
cout << "(Rectangle) Length = " << length << "\nWidth = " << width
<< endl;
}
};
class Area : public Rectangle {
private:
float area;
public:
void calc_area() { area = length * width; }
void result() { cout << "Area = " << area << endl; }
};
class Perimeter : public Rectangle {
private:
float perimeter;
public:
void calc_peri() { perimeter = 2 * (length + width); }
void result() { cout << "Perimeter = " << perimeter << endl; }
};
int main() {
Rectangle R1;
Area* A1;
Perimeter P1;
Rectangle* ptr;
R1.getdata();
ptr = &R1;
A1 = static_cast<Area*>(ptr);
// or:
// A1 = (Area*)ptr;
ptr->Rectangle::result();
}
Ptr points to the address of a child of class Rectangle (the Area class) and therefore it calls the member (result) of the object it refers to (A1 of type Area)

RTTI behavior not appearing as expected

I have written this code in MS Visual Studio Express 2012 to see the rtti behavior.
But it is not working as expected.
What is wrong in my code?
Shape.h
class Shape
{
public:
Shape(){}
virtual ~Shape(){}
virtual double area() = 0;
};
class Square : public Shape
{
int a;
public:
~Square(){}
Square(int );
virtual double area();
};
class Rectangle : public Shape
{
int l;
int b;
public:
~Rectangle(){}
Rectangle(int,int);
virtual double area();
};
class Circle : public Shape
{
int r;
public:
~Circle(){}
Circle(int);
virtual double area();
};
ShapeMain.cpp
int main()
{
Shape* c = new Circle(4);
cout<< "Area of circle:" << c->area() << endl;
cout << typeid(c).name();
Shape* s = new Square(4);
cout<< "Area of square:" << s->area() << endl;
cout << typeid(s).name();
Shape* r = new Rectangle(4,5);
cout<< "Area of rectangle:" << r->area() << endl;
cout << typeid(r).name();
}
Output
Area of circle:50.24
class Shape * //Expected class Circle*
Area of square:16
class Shape * //Expected class Square*
Area of rectangle:20
class Shape * //Expected class Rectangle*
typeid() only actually performs an RTTI lookup when passed an lvalue of a polymorphic type. Shape is a polymorphic type, but you aren't passing a Shape lvalue, you're passing a Shape*. So when you are passing c, s and r to typeid(), it reports the static type of those expressions, which is Shape*.
To get a run time lookup you can either dereference your pointer: std::cout << typeid(*r).name() << std::endl;
or you can keep references directly:
Circle circle{4};
Shape& c = circle;
cout << "Area of circle:" << c.area() << endl;
cout << typeid(c).name() << endl;

Derived function not returning correct data values

Still working on an inheritance program, the base class is a Shape and there are three derived classes: rectangle, Circle, and Square (Square is derived from Rectangle). When I set the data values trough the respective constructors, I get false values for the data members of each derived class when I display them I'm either not setting them correctly (my guess) or I'm not displaying them correctly. Here is a code snippet.
class Shape
{
public:
Shape(double w = 0, double h = 0, double r = 0)
{
width = w;
height = h;
radius = r;
}
virtual double area() = 0;
void display();
protected:
double width;
double height;
double radius;
};
One derived class:
class Rectangle : public Shape
{
public:
Rectangle(double w, double h) : Shape(w, h)
{
}
double area();
void display();
};
Rectangle's display function:
double Rectangle::area()
{
return width * height;
}
Here is my main():
#include<iostream>
#include "ShapeClass.h"
using namespace std;
int main()
{
Rectangle r(3, 2);
Circle c(3);
Square s(3);
c.display();
s.display();
r.display();
system ("pause");
return 0;
}
Complete ShapeClass.cpp:
#include<iostream>
#include "ShapeClass.h"
using namespace std;
double Shape::area()
{
return (width * height);
}
double Rectangle::area()
{
return width * height;
}
double Circle::area()
{
return (3.14159 * radius * radius);
}
double Square::area()
{
return width * width;
}
void Square::display()
{
cout << "Side length of square: " << width << endl;
cout << "Area of square: " << this->area() << endl;
}
void Circle::display()
{
cout << "Radius of circle: " << radius << endl;
cout << "Area of circle: " << this->area() << endl;
}
void Rectangle::display()
{
cout << "Width of rectangle: " << width << endl;
cout << "Height of rectangle: " << height << endl;
cout << "Area of rectangle: " << this->area() << endl;
}
You need to make your area() function virtual in Rectangle as well:
class Rectangle : public Shape
{
public:
Rectangle(double w, double h) : Shape(w, h)
{
}
virtual double area();
void display();
};
Now, also keep in mind that if you want the display() function to be overriden in specific shapes (in your example I see that Rectangle also has a display() function), then you need to make it virtual as well, in both classes:
virtual void display();
Edit: I tried the following code and it worked perfectly. It's based on your code, so there might be a problem with how you built your project or how you compile/link it.
#include <iostream>
using namespace std;
class Shape
{
public:
Shape(double w = 0, double h = 0, double r = 0)
{
width = w;
height = h;
radius = r;
}
virtual double area() = 0;
virtual void display() = 0;
protected:
double width;
double height;
double radius;
};
class Rectangle : public Shape
{
public:
Rectangle(double w, double h) : Shape(w, h)
{
}
virtual double area() { return width * height; }
virtual void display()
{
cout << "Width of rectangle: " << width << endl;
cout << "Height of rectangle: " << height << endl;
cout << "Area of rectangle: " << this->area() << endl;
}
};
int main(int argc, char* argv[])
{
Rectangle r(3, 2);
r.display();
system ("pause");
return 0;
}