user1778311
user1778311

Reputation:

Double inheritance run-time error in c++

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

Answers (3)

Mike Seymour
Mike Seymour

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

pokey909
pokey909

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

Kerrek SB
Kerrek SB

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

Related Questions