I am trying to implement comparison between different subclasses of the same base class. The comparison should return false if the two instances are of different subclass or return the actual comparison result if they are of the same subclass.
Check the last line in function main: although I have declared equalTo as virtual, only the equalTo method of the base class is called. What is my mistake?
Thanks in advance.
#include <iostream>
#include <fstream>
#include <cmath>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <algorithm>
using namespace std;
bool fileInput = false, fileOutput = false;
class Point
{
public:
double x,y;
Point(){};
Point(double x1, double y1) {
x=x1;
y=y1;
}
bool operator==(Point other) const
{
return (abs(x - other.x) < numeric_limits<double>::epsilon()) and (abs(y - other.y) < numeric_limits<double>::epsilon());
}
};
class Shape
{
protected:
virtual double area() const
{
return 0;
}
virtual void print(std::ostream& os) const {}
virtual void read(std::istream& is) {}
public:
bool compare(Shape* other) {
return area() < other->area();
}
virtual bool equalTo(Shape other) const {
cout << "original";
return false;
}
friend std::ostream& operator<<(std::ostream &strm, const Shape &t)
{
t.print(strm);
return strm;
}
friend std::istream& operator>>(std::istream &strm, Shape &t)
{
t.read(strm);
return strm;
}
};
class Circle : public Shape
{
Point c;
double r;
double area() const
{
return M_PI * r * r;
}
void print(std::ostream &strm) const
{
strm << "Circle. Center coordinates: (" << c.x << "," << c.y << "). Radius: " << r << ". Area: " << area();
}
void read(std::istream &strm)
{
if (!fileInput) cout << "Enter Circle\nCenter: ";
strm >> c.x >> c.y;
if (!fileInput) cout << "Radius: ";
strm >> r;
if (r<0)
throw std::invalid_argument( "The radius cannot be negative." );
}
public:
Circle() {}
Circle(Point x, double y)
{
c = x;
r = y;
}
bool equalTo(Shape other1) const
{
Circle* other = dynamic_cast<Circle*>(&other1);
if (other == 0) return false;
return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
}
};
class Hexagon : public Shape
{
Point c;
double r;
double area() const
{
return 1.5 * sqrt(3) * r * r;
}
void print(std::ostream &strm) const
{
strm << "Hexagon. Center coordinates: (" << c.x << "," << c.y << "). Circumcircle radius: " << r << ". Area: " << area();
}
void read(std::istream &strm)
{
if (!fileInput) cout << "Enter Hexagon\nCenter: ";
strm >> c.x >> c.y;
if (!fileInput) cout << "Circumcircle radius: ";
strm >> r;
if (r<0)
throw std::invalid_argument( "The circumcircle radius cannot be negative." );
}
public:
Hexagon() {}
Hexagon(Point x, double y)
{
c = x;
r = y;
}
bool equalTo(Shape other1) const
{
Hexagon* other = dynamic_cast<Hexagon*>(&other1);
if (other == 0) return false;
return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
}
};
int main()
{
Shape c1 = Circle(Point(0,0), 3);
Shape c2 = Circle(Point(0,0), 3);
Shape c3 = Hexagon(Point(0,0), 3);
cout << "circles: " << c1.equalTo(c2) << endl << "diff: " << c1.equalTo(c3) << endl;
}
This is slicing, when you assign objects to object of type Shape - object was sliced to Shape. Use pointers, or may be references.
Circle p1(Point(0, 0), 3);
Circle p2(Point(0, 0), 3);
Hexagon h1(Point(0, 0), 3);
Shape& c1 = p1;
Shape& c2 = p2;
Shape& c3 = h1;
When you copy-construct a Shape out of a derived class, the object will be sliced so that only the Shape part of it is preserved. Then when you call equalTo, the function is statically bound.
In order to call the derived versions, make c1 and friends into Shape&.
Related
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;
I am trying to convert different coordinate systems. From polar to rectangular and vice versa. My pol_to_rect()function is not working properly. It is giving very small values(~10^(-44)) after converting and also before converting. There might be some problem while using the sin() and cos() functions. The rect_to_pol() is working fine for positive values.
Edit - When I changed atan() to atan2() how can I incorporate other values of x and y.
#include <iostream>
#include <cmath>
using namespace std;
#define PI 3.1415926
class Polar; // Forward declaration
class Rectangular {
private:
float x, y;
public:
Rectangular() {} // default constructor
Rectangular(float mv_x, float mv_y) {
x = mv_x;
y = mv_y;
}
void showData() const;
Polar rect_to_pol();
float& get_x() {
return x;
}
float& get_y() {
return y;
}
};
void Rectangular::showData() const {
cout << "--Rectangular--" << endl;
cout << "x: " << x << "\t" <<"y: " << y << endl;
}
class Polar {
private:
float r;
float theta;
public:
Polar() {} // default constructor
Polar(float mv_r, float mv_theta) {
r = mv_r;
theta = mv_theta;
}
void showData();
Rectangular pol_to_rect();
float& get_r(){
return r;
}
float& get_theta() {
return theta;
}
};
void Polar::showData() {
cout << "--Polar--" << endl;
cout << "r:" << r << "\t" << "Theta(Radians):" << theta << endl;
}
Rectangular Polar::pol_to_rect() {
Rectangular temp;
temp.get_x() = r * cos(theta*(PI/180.0)); // in degrees
temp.get_y() = r * sin(theta*(PI/180.0));
return temp;
}
Polar Rectangular::rect_to_pol() {
Polar temp;
temp.get_r() = sqrt(pow(x, 2) + pow(y, 2));
temp.get_theta() = atan2(y, x);
return temp;
}
int main()
{
Rectangular r1(-1, -1), r2;
Polar p1(12.0, 30.0), p2;
r1.showData();
p2 = r1.rect_to_pol();
cout << "After Conversion (RECT TO POLAR)->" << endl;
p2.showData();
p1.showData();
r2 = p1.pol_to_rect();
cout << "After Conversion (POLAR TO RECT)" << endl;
r2.showData();
return 0;
}
I wrote the code that can generate random Geometry figures and display it in cmd in text form.
Here is my 3 files:
Geometry.h
#pragma once
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include <iostream>
#include <time.h>
#include <fstream>
#include <string>
#define PI 3.1415926535
using namespace std;
enum color { White, Red, Green, Blue, Yellow, Black };
enum _shape { line, rectangle, circle, picture }; //to roll shapes
void print_color(color c);
//--------------------------Point---------------------------
class Point {
private:
int m_xc, m_yc; //(x,y) coordinats
public:
Point(int x = 0, int y = 0) : m_xc(x), m_yc(y) {}
int x(void) const { return m_xc; };
int y(void) const { return m_yc; };
Point operator+(const Point& p) const
{
return Point(m_xc+p.m_xc, m_yc+p.m_yc);
}
Point& operator+=(const Point& p) //move point
{
m_xc += p.m_xc;
m_yc += p.m_yc;
return *this;
}
friend ostream& operator<<(ostream& os, const Point& p);
Point move(int x, int y){
m_xc += x;
m_yc += y;
return *this;
}
};
//------------------------Shape-----------------------------
class Shape {
protected:
Point m_org;
color m_color;
_shape m_shape;
public:
Shape(const Point& p1 = 0, color c = White, _shape sh = line) : m_org(p1), m_color(c), m_shape(sh){};
virtual ~Shape() = 0 {};
virtual void move(const Point& p) = 0;
virtual void draw(char tabs) const = 0;
virtual void Who_am_I() const = 0;
virtual double Area() const { return 0; };
virtual void Save2File(ofstream &myfile) const = 0;
};
//------------------------Line---------------------------------
class Line : public Shape {
protected:
Point m_end; // line end
public:
Line(const Point& p1, const Point& p2, color c) : Shape(p1, c, line), m_end(p2) {}
void move(const Point& p)
{
m_org += p;
m_end += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Line";
}
double length() const;
double Area() const { return 0; };
void Save2File(ofstream &myfile) const;
};
//----------------------Rectangle-------------------------------
class Rectangle : public Shape {
protected:
int width;
int height;
public:
Rectangle(const Point& p1, color c = White, int w = 0, int h = 0) : Shape(p1, c, rectangle), width(w), height(h) {}
void move(const Point& p)
{
m_org += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Rectangle";
}
double Area() const { return width*height; };
void Save2File(ofstream &myfile) const;
};
//----------------------Circle---------------------------
class Circle : public Shape {
protected:
int radius;
public:
Circle(const Point& p1, color c = White, int r = 0) : Shape(p1, c, circle), radius(r) {};
void move(const Point& p)
{
m_org += p;
}
void draw(char tabs) const;
void Who_am_I() const {
print_color(m_color);
cout << "Circle";
}
double Area() const { return PI*(double)radius*(double)radius; };
void Save2File(ofstream &myfile) const;
};
//--------------------------Picture-------------------------
class Picture : public Shape {
private:
Picture(const Picture&); //CCtor is not accessible from main
protected:
Shape** m_shapes; //array of pointers to shapes
int m_count; //number of shapes
static unsigned idx; //number of pictures created for debug
public:
Picture(const Point& p1 = 0, color c = White) : Shape(p1, c, picture), m_count(0){ idx++; }
~Picture();
void insert_shape(Shape* sh);
void draw(char tabs) const;
void move(const Point& p){ m_org += p; };
void Who_am_I() const {
print_color(m_color);
cout << "Picture";
}
void Save2File(ofstream &myfile) const;
int get_count(void){ return m_count; }
double Area() const;
unsigned GetAmPic(void) { return idx; }
};
Geometry.cpp
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include "geometry.h"
using namespace std;
unsigned Picture::idx = 0;
ostream& operator<<(ostream& os, const Point& p)
{
os << '(' << p.x() << ',' << p.y() << ')';
return os;
}
void print_color(color c) {
string color_print[6] = { "White ", "Red ", "Green ", "Blue ", "Yellow ", "Black " };
cout << color_print[(int)c];
}
//------------------Line methods--------------------
void Line::draw(char tabs) const
{
cout << string(tabs, '\t');
Who_am_I();
cout << " from " << m_org << " to " << m_end << endl;
}
double Line::length() const
{
return sqrt((double)((m_org.x()-m_end.x())*(m_org.x()-m_end.x()) + (m_org.y()-m_end.y())*(m_org.y()-m_end.y())));
}
void Line::Save2File(ofstream& myfile) const {// save to file
myfile << 'L' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " "
<< m_end.x() << " " << m_end.y() << endl;
}
//------------------Rectangle methods----------------
void Rectangle::draw(char tabs) const
{
cout << string(tabs, '\t');
Point temp1 = m_org;
Point temp2 = m_org;
Line l1(temp1, temp2.move(width, 0), m_color);
temp1 = temp2;
Line l2(temp2, temp1.move(0, height), m_color);
temp2 = temp1;
Line l3(temp1, temp2.move(-width, 0), m_color);
temp1 = temp2;
Line l4(temp2, temp1.move(0, -height), m_color);
Who_am_I(); cout << endl;
cout << string(tabs, '\t'); l1.draw(1);
cout << string(tabs, '\t'); l2.draw(1);
cout << string(tabs, '\t'); l3.draw(1);
cout << string(tabs, '\t'); l4.draw(1);
}
void Rectangle::Save2File(ofstream& myfile) const {// save to file
myfile << 'R' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " " << width
<< " " << height << endl;
}
//----------------------Circle methods---------------------------
void Circle::draw(char tabs) const
{
cout << string(tabs, '\t');
Who_am_I();
cout << " Center in " << m_org << " Radius is " << radius << endl;
}
void Circle::Save2File(ofstream& myfile) const {// save to file
myfile << 'C' << " " << m_color << " " << m_org.x() << " " << m_org.y() << " "
<< radius << endl;
}
//----------------------Picture methods--------------------------
void Picture::insert_shape(Shape* s) // insert a new shape to picture
{
if (m_count == 0) {//new picture creating
m_shapes = new Shape*[1];
if (!m_shapes)
cout << "Can't allocate memory!";
}
if (m_count > 0){
Shape** temp = new Shape*[m_count];
memcpy(temp, m_shapes, sizeof(Shape*)*m_count); //save to temp
delete m_shapes; //delete old array
m_shapes = new Shape*[m_count + 1]; //add 1 more place
if (!m_shapes)
cout << "Can't allocate memory!";
memcpy(m_shapes, temp, sizeof(Shape*)*m_count); //return to array
delete temp;
}
m_shapes[m_count] = s; // insert the new shape into the last slot in the array
m_shapes[m_count]->move(m_org); //adjusts the location of the shape
m_count++; // increment the number of shapes in picture
}
void Picture::draw(char tabs) const
{
cout << string(tabs, '\t');
cout << "------------------ ";
Who_am_I();
cout << " ----------------------" << endl;
for (unsigned i = 0; i < m_count; i++)
{
m_shapes[i]->draw(tabs + 1); // draw each shape
}
cout << string(tabs, '\t');
cout << "------------------ End ";
Who_am_I();
cout << " ------------------ " << endl;
}
double Picture::Area() const //sum of areas of all shapes in the picture
{
double area = 0;
for (int i = 0; i < m_count; i++)
{
area += m_shapes[i]->Area();
}
return area;
}
Picture::~Picture()
{
for (int i = 0; i < m_count; i++){
if (m_shapes[i])
delete m_shapes[i];
}
Who_am_I(); cout << " deleting..." << endl;
// sometimes (every 5-10 runs) error here. can't reproduce and debug
if (m_shapes)
delete m_shapes;
// seems like program try to delete already freed memory
}
void Picture::Save2File(ofstream& myfile) const // save to file
{
myfile << 'P' << " " << m_color << " " << m_org.x() << " " << m_org.y() << endl;
for (int i = 0; i < m_count; i++)
m_shapes[i]->Save2File(myfile);
myfile << 'E' << endl; // end of a picture
}
drawing_app.cpp
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#include "geometry.h"
#include <iostream>
#define MAX_PICS_IN_PIC 3
#define MAX_SHAPES 5
using namespace std;
void randomizer(Picture*, int); //recursive function
Picture* Load(istream&);
Point GenP(void);
color GenC(void);
int GenLen(void);
int main(void)
{
srand((unsigned int)time(NULL));
Picture *main_pic = new Picture(Point(0, 0), GenC());
ofstream myfile_write("myfile.txt", ios::out);
if (!myfile_write.is_open())
cout << "Can't open file!" << endl;
randomizer(main_pic, MAX_PICS_IN_PIC); //recursive function
main_pic->Save2File(myfile_write); //save picture to file
myfile_write.close();
cout << " Created Picture:" << endl << endl;
main_pic->draw(0); //draw the main picture
cout << "Created: " << main_pic->GetAmPic() << " pictures." << endl; // for debugging
delete[] main_pic;
ifstream myfile_read("myfile.txt", ios::in);
if (!myfile_read.is_open())
cout << "Can't open file!" << endl;
Picture* buff_pic = Load(myfile_read); //load the picture from the file
cout << endl << endl << " Loaded Picture:" << endl << endl;
buff_pic->draw(0); //display loaded picture
myfile_read.close();
delete[] buff_pic;
cout << "\nLeaks: " << _CrtDumpMemoryLeaks() << endl;
return 0;
}
void randomizer(Picture* pic, int count) {
for (int i = 0; i < MAX_SHAPES; i++){
Point p1 = GenP(); //m_org of the shape
color c = GenC(); //roll random color
_shape shape;
shape = (_shape)(rand() % 4); //roll random shape
if (shape == line){
Point p2 = GenP();
Line* _line = new Line(p1, p2, c);
pic->insert_shape(_line);
}
if (shape == rectangle){
Rectangle* _rect = new Rectangle(p1, c, GenLen(), GenLen());
pic->insert_shape(_rect);
}
if (shape == circle){
Circle* _circ = new Circle(p1, c, GenLen());
pic->insert_shape(_circ);
}
if (shape == picture){
if (count > 0){
Picture* inner_pic = new Picture(p1, c);
count--;
randomizer(inner_pic, count);
pic->insert_shape(inner_pic);
}
else return;
}
}
}
Picture* Load(istream& myfile) {
int m_color, m_org_x, m_org_y;
char m_shape;
myfile >> m_shape >> m_color >> m_org_x >> m_org_y; //read first line
Picture* pic = new Picture(Point(m_org_x, m_org_y), (color)m_color); //create the main picture
myfile >> m_shape; //read next line for shape
while (m_shape != 'E')
{
if (m_shape == 'L'){
int m_end_x, m_end_y;
myfile >> m_color >> m_org_x >> m_org_y >> m_end_x >> m_end_y;
Line* _line = new Line(Point(m_org_x, m_org_y), Point(m_end_x, m_end_y), (color)m_color);
pic->insert_shape(_line);
}
if (m_shape == 'C'){
int radius;
myfile >> m_color >> m_org_x >> m_org_y >> radius;
Circle* Circel = new Circle(Point(m_org_x, m_org_y), (color)m_color, radius);
pic->insert_shape(Circel);
}
if (m_shape == 'R') {
int m_width, m_height;
myfile >> m_color >> m_org_x >> m_org_y >> m_width >> m_height;
Rectangle* Rect = new Rectangle(Point(m_org_x, m_org_y), (color)m_color,
m_width, m_height);
pic->insert_shape(Rect);
}
if (m_shape == 'P') {
myfile.seekg(-1, ios::cur);
Picture* inner_pic = Load(myfile);
pic->insert_shape(inner_pic);
}
myfile >> m_shape;
}
return pic;
}
Point GenP(){ //roll random point x = 0 to 30, y = 0 to 30
Point p(rand() % 31, rand() % 31);
return p;
}
color GenC(){ //generate random color
return (color)(rand() % 6);
}
int GenLen(){ // generate random length from 1 to 50
return rand() % 50 + 1;
}
Every 5-10 runs I got strange error:
Unhandled exception at 0x5214A9E8 (msvcr120d.dll) in Geometry.exe: 0xC0000005: Access violation reading location 0xCDCDCDC1.
Referring me to Destructor of Picture class. I can't reproduce this error and can't find the source of this error. Do you have any ideas how I can debug it?
The obvious error is that it is entirely (and easily) possible to attempt to delete an uninitialized m_shapes pointer in the Picture destructor.
The outline of your code is this:
class Picture : public Shape {
private:
Picture(const Picture&); //CCtor is not accessible from main
protected:
Shape** m_shapes; //array of pointers to shapes
int m_count; //number of shapes
static unsigned idx; //number of pictures created for debug
public:
Picture(const Point& p1 = 0, color c = White) : Shape(p1, c, picture), m_count(0){ idx++; }
//...
~Picture();
};
In the ~Picture() function, you do the following:
Picture::~Picture()
{
for (int i = 0; i < m_count; i++){
if (m_shapes[i])
delete m_shapes[i];
}
if (m_shapes) // This may not have been initialized!!
delete m_shapes;
}
In the Picture() constructor, you failed to initialize m_shapes, thus a simple one line program would be able to invoke the undefined behavior of calling delete on an uninitialized pointer.
Example:
int main()
{
Picture p(Picture(Point(0, 0), GenC()));
} // The `p` destructor will invoke undefined behavior.
Therefore the immediate fix is to go back and make sure m_shapes is initialized to (at least) a nullptr on construction of Picture.
However the ultimate fix is to start to use std::vector and other containers, in addition to using smart pointers such as std::shared_ptr<Shape> and/or std::unique_ptr<Shape>. When you do this, functions such as Picture::insert_shape become either obsolete, or are simple one-line functions issuing a call to (for example) std::vector<Shape*>::push_back().
For example (using a vector of raw pointers)
#include <vector>
class Picture
{
//...
std::vector<Shape *> m_shapes;
void insert_shape(Shape* s);
//...
};
void Picture::insert_shape(Shape* s)
{
m_shapes.push_back(s);
}
If you want to debug the crash in C++ code, let me show you how to use and inspect dumps:
Use adplus.exe (get it from Microsoft) and run your app in process monitor mode
Download WinDBG (also from Microsoft)
Use the following command to create a dump in monitor mode of your process
ADPlus -Crash -pmn Geometry.exe -o C:\CrashDumps
Open the crash dump in WinDBG
Learn the power of WinDBG
A note: You might need symbols (.pdb) files to be created/loaded in your dump inspection
The error is in this line.
Picture *main_pic = new Picture(Point(0, 0), GenC());
You're not giving the size to your Picture pointer and you're deleting it like an array, You must assign a size to your pointer then you also can delete is like this.
delete [] main_pic;
I have problem with those lines in main:
*tab[1]=test1;
*tab[4]=test2;
It just adds colour, and variables (a,b,h) stay the same. I was trying something like this
cuboid operator=(const cuboid & base)
{
return cuboid(base.colour(), base.valueA(), base.valueB(),base.h_)
}
but this doesn't seem to be working either
next one is this:
*tab[4] * =2;
There is overloaded operator for this method and when I run this there occures some error. No match for operator*=. Operand types are figure and int.
The last one is: *tab[2] = "bright" + *tab[2]; I think that I need a new constructor for this, but where do I make one?
Thanks for any answer !!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
using namespace std;
class figure
{
string * colour_;
public:
figure(): colour_(new string("Empty")) {}
figure(const string & colour): colour_(new string(colour)) {}
figure(const figure & base)
{
colour_=new string(*base.colour_);
}
virtual ~figure() {delete colour_;}
string & colour () const {return *colour_;}
virtual double area () =0;
virtual void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
}
friend ostream & operator <<(ostream &os, const figure & base)
{
base.print(os);
return os;
}
figure & operator=(const figure & base)
{
if(this==&base)
return *this;
else
{
colour_=new string(*base.colour_);
return *this;
}
}
};
class circle :public figure
{
int r_;
public:
circle() : r_(0) {}
circle(const string & colour,const int r) : figure(colour), r_(r) {}
double area()
{
return M_PI*r_*r_;
}
const int & radius() const {return r_;}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Radius: " << radius() << " ";
}
circle & operator=(const circle & base)
{
r_=base.r_;
figure::operator=(base);
return *this;
}
};
class rectangle : public figure
{
int a_;
int b_;
public:
static int ObjectCount_;
rectangle() : a_(0), b_(0) {++ObjectCount_;}
rectangle(const string & colour, const int a, const int b) : figure(colour),a_(a), b_(b) {++ObjectCount_;}
~rectangle() {--ObjectCount_;}
double area()
{
return a_*b_;
}
const int & valueA () const {return a_;}
const int & valueB () const {return b_;}
int & changeA() {return a_;}
int & changeB() {return b_;}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Value A: " << valueA() << " ";
where << "Value B: " << valueB() << " ";
}
rectangle & operator=(const rectangle & base)
{
a_=base.a_;
b_=base.b_;
return *this;
}
static int & ObjectCount() {return ObjectCount_; }
};
class cuboid :public rectangle
{
int h_;
public:
cuboid() : h_(0) {}
cuboid(const string & colour, const int a, const int b, const int h) : rectangle(colour,a,b), h_(h) {}
double area()
{
return 2*valueA()*valueB()+2*valueB()*h_+2*valueA()*h_;
}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Value A: " << valueA() << " ";
where << "Value B: " << valueB() << " ";
where << "Height: " << h_ << " ";
}
cuboid & operator=(const cuboid & base)
{
figure::operator=(base);
rectangle::operator=(base);
h_=base.h_;
return *this;
}
cuboid & operator*=(const int number)
{
h_*=number;
changeA()*=number;
changeB()*=number;
return *this;
}
};
int rectangle::ObjectCount_=0;
int main()
{
figure * tab[5];
const circle test1("black",100);
const cuboid test2("grey", 2,2,2);
tab[0]=new circle("red",1);
tab[1]=new circle;
tab[2]=new rectangle("blue",1,1);
tab[3]=new cuboid("green",1,1,1);
tab[4]=new cuboid;
for(unsigned i=0; i<5;++i)
cout << tab[i]->area() << endl;
for(int i=0; i<5; ++i)
cout<<*tab[i]<<tab[i]->area()<<"\n";
cout << "***********************" << endl;
*tab[1]=test1; // it just assigns a colour, rest stays the same
*tab[4]=test2; // same here
/*
*tab[2] = "bright" + *tab[2]; //?????
*/
//*tab[4]*=2; //some error, no idea
for(int i=0; i<5; ++i)
cout<<*tab[i]<<tab[i]->area()<<"\n";
cout << "$ " << rectangle::ObjectCount() << endl;
for(int i=0; i<5; i++)
delete tab[i];
cout << "$ " << rectangle::ObjectCount() << endl;
}
You are defining array figure* tab[5], so then you make an assigments you are casting all pointers to your objects to figure*:
tab[0]=new circle("red",1);
tab[1]=new circle;
tab[2]=new rectangle("blue",1,1);
tab[3]=new cuboid("green",1,1,1);
tab[4]=new cuboid;
Class figure have only this assigment operator:
figure & operator=(const figure & base) {
if(this==&base)
return *this;
else {
colour_=new string(*base.colour_);
return *this;
}
}
So, then you are doing:
*tab[1]=test1;
*tab[4]=test2;
you are calling that assigment operator from class figure.
Same with operator *=. class figure just doesn't
have it. Thats why you are getting error.
I need to write program as follow:
#include <iostream>
using namespace std;
class Point
{
public:
double X;
double Y;
Point(){}
Point(double x, double y)
{
X = x;
Y = y;
}
};
class Circle
{
public:
Point P;
double R;
Circle(){}
Circle(Point p, double r)
{
P = p;
R = r;
}
Circle operator +(Circle C1, Circle C2)
{
return Circle(C1.Point, C1.R + C2.R);
}
Circle operator -(Circle C1, Circle C2)
{
return Circle(C2.Point, C1.R - C2.R);
}
};
int main()
{
Circle c1, c2, cr1, cr2, ck1, ck2;
// create c1
// create c2
cr1 = c1 + c2;
// display cr1
cr2 = c2 + c1;
// display cr2
ck1 = c1 - c2;
// display ck1
ck2 = c2 - c1;
// display ck2
return 0;
}
Two classes Point and Circle, where Circle have member of Point as it's center, two operators to add and to subtract two Circles.
And I can't compile this, what is wrong?
#################################################################################
EDIT:
After correction it looks like that, and works perfectly:
#include <iostream>
using namespace std;
class Point
{
public:
double X, Y;
Point(){}
Point(double x, double y)
{
X = x;
Y = y;
}
};
class Circle
{
public:
double R;
Point P;
Circle(){}
Circle(Point p, double b)
{
P = p;
R = b;
}
Circle operator+(const Circle& C1)
{
Circle C;
C.P = this->P;
C.R = this->R + C1.R;
return C;
}
Circle operator -(const Circle& C1)
{
Circle C;
C.P = C1.P;
C.R = this->R - C1.R;
return C;
}
};
int main()
{
double X, Y, R;
cout << "Coordinates for C1:" << endl;
cout << "\tX: ";
cin >> X;
cout << "\tY: ";
cin >> Y;
cout << "Radius for C1:";
cin >> R;
Circle *c1 = new Circle(Point(X, Y), R);
cout << "Coordinates for C2:" << endl;
cout << "\tX: ";
cin >> X;
cout << "\tY: ";
cin >> Y;
cout << "Radius for C2:";
cin >> R;
Circle *c2 = new Circle(Point(X, Y), R);
Circle cs1 = c1->operator+(*c2);
Circle cs2 = c1->operator-(*c2);
Circle cr1 = c2->operator+(*c1);
Circle cr2 = c2->operator-(*c1);
cout << "cs1([" << cs1.P.X << ", " << cs1.P.Y << "], " << cs1.R << ")" << endl;
cout << "cs2([" << cs2.P.X << ", " << cs2.P.Y << "], " << cs2.R << ")" << endl;
cout << "cr1([" << cr1.P.X << ", " << cr1.P.Y << "], " << cr1.R << ")" << endl;
cout << "cr2([" << cr2.P.X << ", " << cr2.P.Y << "], " << cr2.R << ")" << endl;
char ch;
cin >> ch;
return 0;
}
When you define operators like operator- inside your class as member functions, then when you use it
C3 = C1 + C2;
The compiler is actually calling your member function like
C3 = C1.operator+(C2);
From this you should be able to figure out that operators as member functions only takes one argument, and that the first object in the operator is the this object.
For stand-alone (non-member) functions they need two arguments.
You might want to check e.g. this reference on operator overloading.
You have incorrect overloaded operators. Look at the following code:
Circle operator +(const Circle& C)
{
return Circle(this->P, this->R + C.R);
}
Circle operator -(const Circle& C)
{
return Circle(this->P, this->R - C.R);
}