Reputation:
I'm having a run-time error when running my project which contains the following classes:
Shape
- abstract
Polygon :public Shape
- abstract
Triangle :public Polygon
- normal class
I've created a vector<Shape*> shapes
and when I'm trying in my code do:
shapes[i] = new Triangle(****);
I'm having run-time error.
Is it has something to do with the double inheritance or is it a problem in my code?
Since I've also go a class Circle :public Shape
and when doing
shapes[i] = new Circle(*****);
it all works fine..
edit:
it is vector<Shape*> shapes;
as most of you guessed.
I do not go out of the voctor's boundries
I've changed it to .push_back(new Circle())
and it still just collapse.
The run-time error I get doesn't show any error code, it just shuts the exe file.
Shape is definetly abstract since all my methods are pure virtual
so as Polygon.
I've made my own constructors(in Shape and Polygon) but they do nothing, just blank scope to prevent problem with the default constructor.
Shape.h
#include "Point.h"
class Shape
{
public:
Shape();
//Methods
virtual double get_Perimeter() = 0; //Returns shape's perimeter
virtual double get_Area() = 0; //Returns shape's area
virtual void move(point p) = 0; //Moves the shape
};
Shape.cpp
#include "Shape.h"
shape :: Shape()
{
}
Polygon.h
#include "Point.h"
#include "Shape.h"
#include <vector>
using namespace std;
class Polygon :public Shape
{
protected:
//Fields
vector<point> points; //Vector of the polygon's points
public:
//Constructors
Polygon();
//Methods
virtual int getNumOfPoints() = 0; //Returns number of points
virtual vector<double> get_Sides() = 0; //Returns vector of side's length
virtual vector<point> get_Points() = 0; //Returns vector of points
virtual double get_Perimeter() = 0; //Returns shape's perimeter
virtual double get_Area() = 0; //Returns shape's area
virtual void move(point p) = 0; //Moves the shape
};
Polygon.h
#include "polygon.h"
polygon :: polygon()
{
}
Point.h
class point
{
protected:
//Fields
double x; //the X value of point
double y; //the Y value of point
public:
//Constructors
point(double x, double y); //Creates new point with given params
point(const point &other); //Creates new point with other point's params
//Methods
double get_X() const; //Returns X field
double get_Y() const; //Returns Y field
void move(int dx, int dy); //Adds given params to current params
void move(point p); //Adds p's params to current params
};
main.cpp
vector<shape*> shapes;
//Creating new tirangle
point* p1 = new point(1,1);
point* p2 = new point(5,1);
point* p3 = new point(3,4);
shapes.push_back(new triangle(*p1,*p2,*p3));
Triangle.h
#include "point.h"
#include "polygon.h"
#include <vector>
using namespace std;
class triangle :public polygon
{
public:
//Constructors
triangle(point p1, point p2, point p3); //Creates new triangle with given params
triangle(const triangle &other); //Copies other's params to new triangle
//Methods
point get_P1() const; //Returns p1
point get_P2() const; //Returns p2
point get_P3() const; //Returns p3
int getNumOfPoints(); //Returns number of points
vector<double> get_Sides(); //Returns vector of side's length
vector<point> get_Points(); //Returns vector of points
double get_Perimeter(); //Returns shape's perimeter
double get_Area(); //Returns shape's area
void move(point p); //Moves the shape
};
Triangle.cpp
#include "triangle.h"
#include <cmath>
//Constructors
triangle :: triangle(point p1, point p2, point p3)
{
points[0] = p1;
points[1] = p2;
points[2] = p3;
}
triangle :: triangle(const triangle &other)
{
points[0] = other.get_P1();
points[1] = other.get_P2();
points[2] = other.get_P3();
}
//Methods
point triangle :: get_P1() const
{
return points[0];
}
point triangle :: get_P2() const
{
return points[1];
}
point triangle :: get_P3() const
{
return points[2];
}
int triangle :: getNumOfPoints()
{
return points.size();
}
vector<double> triangle :: get_Sides()
{
vector<double> sides;
sides[0] = sqrt(pow(points[0].get_X()-points[1].get_X(),2)+pow(points[0].get_Y()-points[1].get_Y(),2));
sides[1] = sqrt(pow(points[1].get_X()-points[2].get_X(),2)+pow(points[1].get_Y()-points[2].get_Y(),2));
sides[2] = sqrt(pow(points[2].get_X()-points[0].get_X(),2)+pow(points[2].get_Y()-points[0].get_Y(),2));
return sides;
}
vector<point> triangle :: get_Points()
{
return points;
}
double triangle :: get_Perimeter()
{
vector<double> sides = this->get_Sides();
return sides[0]+sides[1]+sides[2];
}
double triangle ::get_Area() //By Heron's Formula
{
vector<double> sides = this->get_Sides();
double area = this->get_Perimeter()/2;
double tmp = area;
for(int i=0;i<3;i++)
area*=(tmp-sides[i]);
return sqrt(area);
}
void triangle :: move(point p)
{
for(int i=0;i<3;i++)
{
points[i].move(p);
}
}
Upvotes: 0
Views: 247
Reputation: 254631
The problem is the constructor of triangle
:
triangle :: triangle(point p1, point p2, point p3)
{
points[0] = p1;
points[1] = p2;
points[2] = p3;
}
This attempts to write to elements of an empty vector; you can only use []
to access vector elements if the vector is large enough. You should use push_back()
to grow the vector:
points.push_back(p1);
points.push_back(p2);
points.push_back(p3);
or, if you can use C++11, assign from an initialiser list:
points = {p1, p2, p3};
Likewise for the copy constructor; although there's no point declaring a copy constructor at all since the implicitly-generated one will correctly copy the vector of points.
Veering slightly off-topic, be very careful if you're using a container of raw pointers to manage object lifetimes: it's very easy to accidentally remove a pointer without deleting the object, leaking memory. I'd suggest using smart pointers.
There's also another potential problem: Shape
doesn't have a virtual destructor, which means you can't delete any of the shapes in your vector; doing so could cause a crash. You should one:
virtual ~Shape() {}
Upvotes: 0
Reputation: 1837
basically what Kerres said. Just an additional note which might be relevant in similar cases.
If your Shape
class were not abstract and you used
std::vector<Shape> shapes;
then this
shapes[i] = Circle(***);
would be valid, but your object would get sliced! Which means, all information in the further derived classes are lost. This is an important fact to remember!
Upvotes: 0
Reputation: 477368
A vector can only store objects of identical type. What you need is a container of owning pointers:
#include <vector>
#include <memory>
std::vector<std::unique_ptr<Shape>> shapes;
shapes.emplace_back(new Triangle);
shapes.emplace_back(new Circle);
Upvotes: 3