Given following classes:
class Geometry {
public:
double distanceBetweenGeometries(const Geometry& g);
private:
Shape myShape;
};
class Shape {
public:
double distance(const Shape& s1, const Shape& s2);
};
class Rectangle : public Shape {
private:
double i,j,length,width;
};
class Circle : public Shape {
private:
double i,j,radius;
};
So each geometry got a shape of type Rectangle or Circle. In my program I need to calculate the (Euclidean) distance between two geometries. Thus, given two geometries g1 and g2 I call
g1.distanceBetweenGeometries(g2);
and I want to return the distance between g1.myShape and g2.myShape.
I already know how to calculate the distance between two rectangles, two circles or between a rectangle and a circle. Somehow, I did not achieve an object-orientated solution for implementing the distance-function.
My idea is: Call the distance-function from a given geometry. This distance function calls the distance-function of a shape. In Shape::distance(..) I somehow need to differentiate of which type s1 and s2 are. Afterwards, I have to choose the correct mathematical formula to compute the distance between them. Can you tell me if my inheritance-idea is adequate here and how to implement the Shape::distance(..) function so that it can automatically determine which formula is requested for distance-computation?
You may do something like:
class Circle;
class Rectangle;
// Your existing methods to do the real computation:
double distanceRC(const Rectangle&, const Circle&);
double distanceRR(const Rectangle&, const Rectangle&);
double distanceCC(const Circle&, const Circle&);
class Shape {
public:
virtual ~Shape() = default;
virtual double distanceWith(const Shape&) const = 0;
virtual double distanceWith(const Rectangle&) const = 0;
virtual double distanceWith(const Circle&) const = 0;
};
class Rectangle : public Shape {
public:
double distanceWith(const Shape& s) const override { return s.distanceWith(*this); }
double distanceWith(const Rectangle& r) const override { return distanceRR(*this, r);}
double distanceWith(const Circle& c) const override { return distanceRC(*this, c); }
private:
double i,j,length,width;
};
class Circle : public Shape {
public:
double distanceWith(const Shape& s) const override { return s.distanceWith(*this); }
double distanceWith(const Rectangle& r) const override { return distanceRC(r, *this);}
double distanceWith(const Circle& c) const override { return distanceCC(*this, c); }
private:
double i,j,radius;
};
Related
I am getting a compiler error saying that the data member Point p is private within the context, when I declare Point p as private within class circle. The code and compiler error are below.
#include<iostream>
#include<vector>
class Point
{
public:
Point(double a, double b)
{
x = a;
y = b;
}
virtual ~Point(){}
private:
double x;
double y;
};
The code for the class shape and circle are as follows:
class shapes {
public:
virtual Point centre() const = 0;
virtual void draw() const = 0;
virtual void rotate(int angle) const = 0;
virtual ~shapes(){}
};
class circle: public shapes {
public:
Point centre() const override { return p; }
void draw() const override { }
void rotate(int angle) const override {}
virtual ~circle() {}
circle(Point x, int r):p{x},radius{r}{}
private:
Point p;
int radius; };
Edit: Smiley face class inherits from circle class with code below:
class smiley: public circle
{ //smiley face is a circle + eyes and mouth
public:
smiley(Point p, int r):circle{p,r},mouth{nullptr}{}
Point centre() const override { return p;}
void draw() const override
{
//draw circle
circle::draw();
for(auto e:eyes)
{
e->draw();
}
mouth->draw();
}
void rotate(int angle) const {}
virtual ~smiley()
{
delete mouth;
for (auto eye : eyes) //why not delete [] eyes
{
delete eye;
}
}
private:
std::vector<shapes*> eyes; //smiley face has eyes
shapes* mouth; //smiley face has a mouth
};
If I make the data member p public in the class circle, everything works. The compiler error is listed below:
Why can I not define the Point object p, in the circle class private?
Edit: I have added the compiler error message and added the missing code asked for in the comments below. Would you be able to re-open the question?
Private class members can only be accessed within the class or by friends, so, if you would like it to be accessed outside the class by a non-friend, you would need to use a setter/getter.
For example i have three classes
class Shape
{
static bool collide(Box * a, Box * b)
static bool collide(Box * a, Sphere * b)
static bool collide(Sphere * a, Sphere * b)
};
class Box : public Shape{};
class Sphere : public Shape{};
and for example somewhere else i have this piece of code
Shape * a = new Box();
Shape * b = new Sphere();
Shape::collide(a, b);
The compiler raises and error.
How can i automatically downcast objects given as argument without adding too much logic?
The compiler can't cast the objects automatically, you will have to cast them manually, eg:
class Box;
class Sphere;
class Shape
{
virtual ~Shape(){}
static bool collide(Shape *a, Shape *b);
static bool collide(Box *a, Box *b);
static bool collide(Box *a, Sphere *b);
static bool collide(Sphere *a, Sphere *b);
};
class Box : public Shape{};
class Sphere : public Shape{};
bool Shape::collide(Shape *a, Shape *b)
{
if (Box *a_box = dynamic_cast<Box*>(a))
{
if (Box *b_box = dynamic_cast<Box*>(b))
return collide(a_box, b_box);
if (Sphere *b_sphere = dynamic_cast<Sphere*>(b))
return collide(a_box, b_sphere);
}
else if (Sphere *a_sphere = dynamic_cast<Sphere*>(a))
{
if (Sphere *b_sphere = dynamic_cast<Sphere*>(b))
return collide(a_sphere, b_sphere);
}
return false;
}
bool Shape::collide(Box *a, Box *b) { ... }
bool Shape::collide(Box *a, Sphere *b) { ... }
bool Shape::collide(Sphere *a, Sphere *b) { ... }
Shape * a = new Box();
Shape * b = new Sphere();
Shape::collide(a, b);
Needless to say, that can get a bit tedious as new shapes are added. You should instead add a single virtual method to Shape itself and let the derived classes override it to handle different types as needed, eg:
class Shape
{
virtual ~Shape(){}
virtual bool collide(Shape * b) { return false; };
};
class Box : public Shape{
bool collide(Shape * b) override {
if (Box *b_box = dynamic_cast<Box*>(b)) {
return ...;
}
if (Sphere *b_sphere = dynamic_cast<Sphere*>(b)) {
return ...;
}
return Shape::collide(b);
};
};
class Sphere : public Shape{
bool collide(Shape * b) override {
if (Sphere *b_sphere = dynamic_cast<Sphere*>(b)) {
return ...;
}
return Shape::collide(b);
};
};
Shape * a = new Box();
Shape * b = new Sphere();
a->collide(b);
I have this HW question that I have been stuck for hours on that I can't seem to make sense of. It's kind of hard to put to words my actual question but I will try my best. How can I make my outside-member function find the distance between a circle using a class which references another class? In my code below:
//Header
class Point
{
public:
Point();
Point(int, int);
Point(const Point& object);
int getX() const;
int getY() const;
void setX(int);
void setY(int);
double calculate_area();
void print() const;
private:
int x;
int y;
};
class Shape
{
public:
Shape();
double calculate_area();
void print() const;
protected:
double area;
};
class Circle : public Shape
{
public:
Circle();
Circle(const Point&, double);
double getRadius() const;
void setRadius(double);
void calculate_area();
void print() const;
private:
double radius;
Point center;
};
class RTriangle : public Shape
{
public:
RTriangle();
RTriangle(double, double);
double hyp();
void calculate_area();
void print() const;
private:
double side1;
double side2;
};
inline double distance(Circle& other)
{
return sqrt(pow(other.center.x, 2) + pow(other.center.y, 2));
}
#endif
//Implementation.cpp of what i think is important for you guys to see
Point::Point(int inX, int inY) // normal constructor
{
x = inX;
y = inY;
}
Point::Point(const Point &object) // copy constructor needed to use for center of circle
{
x = object.x;
y = object.y;
}
Circle::Circle(const Point& object, double inRad) // center is x & y... radius for circle
{
center = object;
radius = inRad;
}
My outside member function (inline double distance) isn't working. This is the first time I have tried doing this so I apologize if I do not word it well. I am essentially trying to use only the Circle class which inherits point center and point center is defined in the first class as x and y. Is it possible to do such a thing (specifically use x and y which is inside Point center)? I don't know if it's possible to access x and y through center.
Given a Point, functions not in Point can access its x and y members with the public getX() and getY() methods in your example.
However, Circle's center member is not public and has no public accessors. The most straightforward fix would add a public method
Point getCenter(); // or Point const &getCenter() if you like)
to Circle.
Someone recommended me to use boost::variant as shape variable to store different types of shapes in it. But, when implemented boost::variant to my code, I got an error while compiling. Error says: 'Shape': base class undefined and more errors.
Here is my code (Object.h):
using Shape = boost::variant<Rectangle, Circle>;
enum Shape_Type
{
RECTANGLE,
CIRCLE
};
struct Position
{
float x, y;
Position(float position_x, float position_y)
{
x = position_x;
y = position_y;
}
};
class Object : private Shape
{
private:
std::string name;
public:
Object() = default;
Object(std::string name, Rectangle rectangle) : name(name), Shape(rectangle)
{
}
Object(std::string name, Circle circle) : name(name), Shape(circle)
{
}
void setPosition(float, float);
void setAngle(float);
Shape* getShape()
{
Shape* shape = this;
return shape;
}
Position getPosition();
const std::string* getName()
{
return &name;
}
};
class Rectangle
{
private:
sf::RectangleShape rectangleshape;
public:
Rectangle() = default;
Rectangle(float width, float height)
: rectangleshape(sf::RectangleShape(sf::Vector2f(width, height)))
{
}
void setPosition(float position_x, float position_y)
{
rectangleshape.setPosition(position_x, position_y);
}
void setAngle(float angle)
{
rectangleshape.setRotation(angle);
}
sf::RectangleShape* getRectangleShape()
{
return &rectangleshape;
}
Position getPosition()
{
return Position(rectangleshape.getPosition().x,
rectangleshape.getPosition().y);
}
};
class Circle
{
private:
sf::CircleShape circleshape;
public:
Circle() = default;
Circle(std::string name, float radius)
: circleshape(sf::CircleShape(radius))
{
}
void setPosition(float position_x, float position_y)
{
circleshape.setPosition(position_x, position_y);
}
void setAngle(float angle)
{
circleshape.setRotation(angle);
}
sf::CircleShape* getCircleShape()
{
return &circleshape;
}
Position getPosition()
{
return Position(circleshape.getPosition().x,
circleshape.getPosition().y);
}
};
And btw is getShape() function good?
Variants are used for static polymorphism, so you don't need the base class at all (that's dynamic - or virtual - polymorphism).
The members in a variant typically do not share a common base class, so you wouldn't have the getShape function, or you'd need to template it:
template <typename T>
T const& getShape() const { return boost::get<T>(_shape); }
Imagine I have abstract base class Shape, with derived classes Circle and Rectangle.
class Shape {};
class Circle : public Shape {};
class Rectangle : public Shape {};
I need to determine if two shapes are equal, assuming I have two Shape* pointers. (This is because I have two instances of vector<Shape*> and I want to see if they have the same shapes.)
The recommended way to do this is double dispatch. What I've come up with is this (greatly simplified here, so that shapes are equal to all other shapes of the same type):
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
protected:
virtual bool is_equal(Circle& circle) { return false; };
virtual bool is_equal(Rectangle& rect) { return false; };
friend class Circle; // so Rectangle::equals can access Circle::is_equal
friend class Rectangle; // and vice versa
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Rectangle& circle) { return true; };
};
This works, but I have to add a separate equals function and friend declaration in Shape for each derived class. Then I have to copy-paste the exact same equals function into each derived class, too. This is an awful lot of boilerplate for say, 10 different shapes!
Is there a simpler way to do it?
dynamic_cast is out of the question; too slow. (Yes, I benchmarked it. Speed matters in my app.)
I tried this but it doesn't work:
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
private:
virtual bool is_equal(Shape& circle) { return false; };
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Rectangle& circle) { return true; };
};
equals() always returns false, even on identical shapes. It seems dispatch is always choosing the is_equal(Shape&) base function, even when a "more specific" match is available. This probably makes sense but I don't understand C++ dispatch well enough to know why.
When you create methods like this:
virtual bool is_equal(Shape& circle) { return false; };
And in the subclass,
virtual bool is_equal(Circle& circle) { return true; };
These are not the same method. You have two separate virtual methods, neither of which is overridden (they are overloaded not even overloaded, as Ben Voigt pointed out). When you call Shape::is_equal, there is only one version: Shape::is_equal(Shape&)... which is not overridden and always returns false.
You would have to define the separate overloaded methods in the parent class and then override them in the child class. For example,
class Shape {
// Choice between these two methods happens at compile time...
virtual bool is_equal(Circle& circle) { return false; };
virtual bool is_equal(Rectangle& circle) { return false; };
};
class Rectangle : Shape {
// Choice between this and Shape::is_equal(Rectangle&) happens at runtime...
virtual bool is_equal(Rectangle& circle) { return true; };
};
However, using tricks like this, you will probably not approach the performance or simplicity of the way a C programmer would do it:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} shape_type_t;
struct shape {
shape_type_t type;
};
struct circle {
shape_type_t type;
...
};
struct rectangle {
shape_type_t type;
...
};
bool shape_equal(struct shape *x, struct shape *y)
{
if (x->type != y->type)
return false;
switch (x->type) {
case SHAPE_CIRCLE:
return circle_equal((struct circle *) x, (struct circle *) y);
case SHAPE_RECTANGLE:
...;
}
}
If overloading and virtual methods are making your code more complicated than the C version, then you may wish to rethink whether you solve this particular problem with overloading and virtual methods.
Double-dispatch has been well studied. The generalization of double-dispatch is called a "multi-method".
Chapter 11 of Modern C++ Design addresses this issue in detail. The approach using dynamic_cast<> that you described is in section 11.3 "Double Switch-on-Type: Brute Force". The author even describes how to automate most of the work and automatically generate the symmetric overloads. Then, the author introduces a logarithmic dispatch based on std::map<> and std::type_info. Finally, the section ends with "Constant-Time Multimethods: Raw Speed" that's (roughly) based on a matrix of callback functions.
The presented solution includes lengthy explanations on handling functors and casts to avoid nasty pitfalls in presence of multiple (and virtual) inheritance.
If you consider implementing multi-methods in C++, I stronly recommend that you read the book and implement the proposed solution.
You could use a type enumeration and static casting if dynamic_cast is too slow...
enum ShapeType
{
SHAPE_TYPE_CIRCLE,
SHAPE_TYPE_RECTANGLE
};
struct Shape
{
virtual ShapeType GetShapeType() const = 0;
virtual bool isEqual(const Shape& other) const = 0;
};
struct Circle : Shape
{
virtual ShapeType GetShapeType() const { return SHAPE_TYPE_CIRCLE; }
virtual bool isEqual(const Shape& other) const
{
if (other.GetShapeType() == SHAPE_TYPE_CIRCLE)
{
const Circle *circle = static_cast<const Circle*>(&other);
// do some circle specific comparison
return true;
}
return false;
}
};
Virtual functions can easily replace dynamic_cast RTTI type-checking, like this: http://ideone.com/l7Jr5
struct Shape
{
struct subtype { enum { Shape, Circle, Rectangle, ColoredCircle }; };
virtual bool is_a( int type ) const { return type == subtype::Shape; }
virtual bool is_equal(const Shape& s) const { return false; }
};
struct Rectangle : Shape
{
virtual bool is_a( int type ) const { return type == subtype::Rectangle || Shape::is_a(type); }
virtual bool is_equal(const Shape& s) const
{
if (!s.is_a(subtype::Rectangle)) return false;
const Rectangle& r = static_cast<const Rectangle&>(s);
return true; // or check width and height
}
};
struct Circle : Shape
{
virtual bool is_a( int type ) const { return type == subtype::Circle || Shape::is_a(type); }
virtual bool is_equal(const Shape& s) const
{
if (!s.is_a(subtype::Circle)) return false;
const Circle& c = static_cast<const Circle&>(s);
return true; // or check radius
}
};
struct ColoredCircle : Circle
{
virtual bool is_a( int type ) const { return type == subtype::ColoredCircle || Circle::is_a(type); }
};
int main(void)
{
Rectangle x;
Shape y;
return x.is_equal(y);
}
--
Why are there 10 copies of the "exact same" function? Shouldn't Rectangle::is_equal(const Rectangle&) const be comparing Rectangle-specific members?
If all rectangles fall into a single equivalence class, as is the case with the code you showed, then you can just have a single virtual function that returns the equivalence class.
In my designs, I move the Shape::operator== method to private and not implement it. The amount of work to correctly resolve this is not worth the effort.
In other words, given a vector of Shape *:
std::vector<Shape *> my_shapes;
I can do the following:
my_shapes.push_back(new Rectangle);
my_shapes.push_back(new Circle);
The problem comes in when comparing objects:
Shape * p_shape_1 = my_shapes[0];
Shape * p_shape_2 = my_shapes[1];
if (*p_shape_1 == *p_shape_2) {...}
The expression is equivalent to:
p_shape_1->operator==(*p_shape_2);
If a virtual or polymorphic operation is in place, this becomes:
Rectangle::operator==((Circle));
In otherwords, there is a great possibility that Rectangle will be comparing itself to a Circle or other Shape; an invalid comparison.
So, in my designs I prohibit equality comparisons based on base class pointers. The only stuff that can be compared using pointers to base classes is the content in the base class.
I usually refer to dynamic_cast and virtual funcntions. If the compiler is not too dumb, dynamic casting one step is not that different than making two jumps in a vtable.
class shape
{
protected:
virtual bool is_equal(const shape* s) const=0;
friend bool oeprator==(const shape& a, cost shape& b)
{ return a.is_equal(&b); }
};
class circle: public shape
{
double radius;
point<duouble> center;
protected:
virtual bool is_equal(const shape* s) const
{
const circle* p = dynamic_cast<const circle*>(s);
return p && p->radius==radius && p->center==center;
}
};
Same for rectangle or whatever other shape.
basically, dual dispatch requires - if N are the classees, N2 functions.
In this way, you just need N functions (one per class).
If you feel dynamic cast to be too slow, you can use an enum, declared in the base class,
and initialized properly by the derived classes.
But this requires you to update the enum values every time a new class will be added.
For example:
class shape
{
protected:
enum shapes_type { no_shape, circle_shape, rectangle_shape };
shapes_type my_type;
virtual bool is_equal(const shape* s) const=0;
friend bool oeprator==(const shape& a, cost shape& b)
{ return a.is_equal(&b); }
shape() :my_type(no_shape)
{}
};
class circle: public shape
{
double radius;
point<duouble> center;
protected:
virtual bool is_equal(const shape* s) const
{
const circle* p = static_cast<const circle*>(s);
return my_type == s->my_type && p->radius==radius && p->center==center;
}
public:
circle() { my_type = circle_shape; }
};
In case relying on a base_defined enum is not acceptable (not known number of possible classes), you can rely on a simple value (e.g.: an integer) that can represent univocally a type with a trick like:
int int_generator()
{ static int x=0; return ++x; }
template<class T>
int id_for_type()
{ static int z = int_generator(); return z; }
class shape
{
...
int my_type;
};
class circle
{
...
circle() { my_type = id_for_type<circle>(); }
};