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>(); }
};
Related
I have a polymorphic value type implemented like so:
class ShapeValue {
public:
template<class T>
ShapeValue(const T& value) {
obj = make_unique<holder<T>>(value);
}
// ... appropriate copy constructors and such
void draw() { obj->draw(); }
private:
struct base {
virtual ~base() {}
virtual void draw() = 0;
};
template<class T>
struct holder<T> : public base {
T value;
void draw() override { value.draw(); }
}
unique_ptr<base> obj;
};
If you aren't familiar with this sort of thing, here's a good talk.
Ok, that's great. But now what if I want to cast my underlying object to some other interface?
Here's my motivation. Previously, I had defined things the typical way, like so:
class Shape {
virtual void draw() = 0;
};
and then I would define other interfaces, like:
class HasColor {
virtual Color color() = 0;
virtual void setColor(Color) = 0;
};
so I could define a shape as follows:
class MyShape : public Shape, public HasColor {
void draw() override;
Color color() override;
void setColor(Color) override;
};
So if I have a bunch of selected shapes and I want to set their color, I could iterate over all shapes and dynamic_cast<HasColor*>. This proves to be quite convenient (my actual app isn't a drawing app, by the way, but has analogous data).
Can I do this for my polymorphic value type, in a way that my ShapeValue interface doesn't need to know about every Has interface? I could do the following, which isn't actually so bad, but not ideal:
HasColor* ShapeValue::toHasColor() { return obj->toHasColor(); }
A solution (tested) is to have a base class for the interfaces:
class AnyInterface {
virtual ~AnyInterface() {} // make it polymorphic
};
struct HasColor : public AnyInterface {
// ... same stuff
};
So then we have the following:
vector<AnyInterface*> ShapeValue::getInterfaces() { return _obj->getInterfaces(); }
Could then define a helper to grab the interface we want:
template<class I>
I* hasInterface(Shape& shape) {
for(auto interface : shape.getInterfaces()) {
if(auto p = dynamic_cast<I*>(interface)) {
return p;
}
}
return nullptr;
}
This way ShapeValue does not need to know about all the interface types.
The accepted answer seems likely a viable solution though I haven't tested it and it does seem to fallback to reference semantics. A motivating factor however for polymorphic value types is instead value semantics.
What follows is a description of a more value semantic oriented alternative solution where ShapeValue doesn't need to know about all the interface types, albeit external user-definable free functions sort of do instead.
As I've been using polymorphic value types, I've preferred to recognize two categories of functionality of those values:
Functionality required of all eligible value types. I.e. the functionality enforced by the virtual methods of this base polymorphic concept class.
Optional/extended functionality which some, none, or all eligible value types may provide.
It seems like your question is more about how to deal this second category (than the first).
For this second category, I've borrowed on the implementation of std::any's type member function and std::any's non-member any_cast template functions. With these two functional concepts, the set of value types, which implement some optional extended functionality, is open (like namespaces are open to additions contrary to classes) and your ShapeValue's interface doesn't need to know about every optional extension. As an added bonus, no extended functionality needs to be implemented using type polymorphism - i.e. the value types eligible for use with ShapeValue construction, don't have to have any kind of inheritance relationship or virtual functions.
Here's an example of pseudo code extending the question's code for this:
class ShapeValue {
public:
template<class T>
ShapeValue(const T& value) {
obj = make_unique<holder<T>>(value);
}
// ... appropriate copy constructors and such
ShapeValue& operator=(const ShapeValue& newValue) {
obj = newValue.obj? newValue.obj->clone(): nullptr;
return *this;
}
const std::type_info& type() const noexcept {
return obj? obj->type_(): typeid(void);
}
void draw() { obj->draw(); }
template <typename T>
friend auto type_cast(const ShapeValue* value) noexcept {
if (!value || value->type() != typeid(std::remove_pointer_t<T>))
return static_cast<T>(nullptr);
return static_cast<T>(value->obj->data_());
}
private:
struct base {
virtual ~base() = default;
virtual void draw() = 0;
virtual std::unique_ptr<base> clone_() const = 0;
virtual const std::type_info& type_() const noexcept = 0;
virtual const void* data_() const noexcept = 0;
};
template<class T>
struct holder final: base {
T value;
void draw() override { value.draw(); }
std::unique_ptr<base> clone_() const override {
return std::make_unique<holder>(value);
}
const std::type_info& type_() const noexcept override { return typeid(T); }
const void* data_() const noexcept override { return &value; }
};
unique_ptr<base> obj;
};
template <typename T>
inline auto type_cast(const ShapeValue& value)
{
auto tmp = type_cast<std::add_pointer_t<std::add_const_t<T>>>(&value);
if (tmp == nullptr)
throw std::bad_cast();
return *tmp;
}
struct Square {
int side_;
Color color_;
void draw();
Color color() { return color_; }
void setColor(Color value) { color_ = value; }
};
Color color(const ShapeValue& value)
{
if (value.type() == typeid(Square)) {
return type_cast<Square>(value).color();
}
throw std::invalid_argument("color not supported for value's type");
}
void setColor(ShapeValue& value, Color newColor)
{
if (value.type() == typeid(Square)) {
auto square = type_cast<Square>(value);
square.setColor(newColor);
value = square;
return;
}
throw std::invalid_argument("setColor not supported for value's type");
}
For a more elaborate, compilable, tested, and typeid/std::type_info-free example, one can take a look at the source code for the Joint polymorphic value type I just finished that provides an interface to value types for constraining the movements of one or more bodies. I wouldn't say it's perfect, but it's also more value semantics oriented like the example above that I've included in this answer.
I've got the following code currently (not working):
#include <iostream>
#include <vector>
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
};
class Creator {
public:
virtual ~Creator() {};
virtual Shape* create() = 0;
virtual bool equals(Shape& s) { return false; };
};
class Circle : public Shape {
private:
Circle() : Shape() {};
public:
class CircleCreator : public Creator {
public:
virtual Shape* create() { return new Circle(); };
virtual bool equals(Shape& other_shape) { return false; };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {};
public:
class RectangleCreator : public Creator {
public:
virtual Shape* create() { return new Rectangle(); };
virtual bool equals(Shape& other_shape) { return false; };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
My goal is to use a factory pattern and avoid the creation of a new object if in a list I've got already that object. I tried to use a double dispatch pattern but it isn't easy to apply in this case. How can I do?
Edit: Since the code is used in a "critical" path, I want to avoid RTTI like dynamic_cast and so on.
Maybe something like this could do it using member variables
#include <iostream>
#include <vector>
enum
{
CIRCLE,
RECTANGLE
};
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
unsigned shapeType;
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
};
class Creator {
public:
unsigned shapeType;
virtual ~Creator() {};
virtual Shape* create() = 0;
bool equals(Shape& s) { return (this->shapeType == s.shapeType); };
};
class Circle : public Shape {
private:
Circle() : Shape() {shapeType=CIRCLE;};
public:
class CircleCreator : public Creator {
public:
CircleCreator() {shapeType=CIRCLE;};
virtual Shape* create() { return new Circle(); };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {shapeType=RECTANGLE;};
public:
class RectangleCreator : public Creator {
public:
RectangleCreator() {shapeType=RECTANGLE;};
virtual Shape* create() { return new Rectangle(); };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
or this - using virtual function to return type
#include <iostream>
#include <vector>
enum
{
CIRCLE,
RECTANGLE,
UNKNOWN
};
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
virtual unsigned iAmA(){return UNKNOWN;};
};
class Creator {
public:
virtual ~Creator() {};
virtual Shape* create() = 0;
virtual bool equals(Shape& s) { return false; };
};
class Circle : public Shape {
private:
Circle() : Shape() {};
virtual unsigned iAmA(){return CIRCLE;};
public:
class CircleCreator : public Creator {
public:
CircleCreator() {};
virtual Shape* create() { return new Circle(); };
virtual bool equals(Shape& other_shape) { return (CIRCLE == other_shape.iAmA()); };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {};
virtual unsigned iAmA(){return RECTANGLE;};
public:
class RectangleCreator : public Creator {
public:
RectangleCreator() {};
virtual Shape* create() { return new Rectangle(); };
virtual bool equals(Shape& other_shape) { return (RECTANGLE == other_shape.iAmA()); };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
I'm not sure what you're trying to do, but I guess this could point you some direction
enum class Shapes
{
Rectangle,
Circle,
...
};
class Shape
{
private:
Shapes m_shape;
protected:
Shape(Shapes shape)
{
m_shape = shape;
}
public:
Shapes GetShape() { return m_shape; } // this is used to check whether two shapes are equal
virtual ~Shape() = default;
};
And now for factory pattern you'd do:
class ShapeFactory
{
public:
static Shape* CreateShape(Shapes shape)
{
switch (shape)
{
case Shapes::Circle:
return new Circle();
// etc.
}
}
};
This feels very redundant and not very clever to me. Also, this can put alot of code into one place.
For the dispatch, you could do (I assume, I'm not really a fan of this concept as it can be made less verbose with a simple template use)
class ShapeCreator
{
public:
virtual Shape* Create() = 0;
virtual ~ShapeCreator() = default;
};
class Circle : public Shape
{
public:
class Creator : ShapeCreator
{
public:
Shape* Create() { return new Circle(); }
};
Circle() : Shape(Shapes::Circle)
{}
};
bool SomethingWithCircle()
{
Circle::Creator circleCreator;
Shape* first = circleCreator.Create();
Shape* second = circleCreator.Create();
// notice memleak here
return first->GetShape() == second->GetShape();
}
If using C++11, you can go even further and avoid the whole idea /which feels very java-like to me anyway/ using a proper template masturbation techniques. (Can still be applied to pre-C++11, you just won't be able specify the parameters.)
template<class T>
class ShapeCreator
{
public:
template<class... TParams>
static T* Create(TParams&&... parameters) { return new T(std::forward<TParams>(parameters)...); }
};
class Rectangle : public Shape
{
private:
int m_width;
int m_height;
public:
Rectangle(int width, int height) : Shape(Shapes::Rectangle)
{
m_width = width;
m_height = height;
}
};
bool DoSomethingWithRectangles()
{
Rectangle* first = ShapeCreator<Rectangle>::Create(10, 15);
Shape* second = ShapeCreator<Rectangle>::Create(20, 25);
// notice memleak here
return first->GetShape() == second->GetShape();
}
TL;DR
You don't really need RTTI but you need to store the type info somewhere in the base type. I'm using the enum Shapes for this.
Both Factory and Dispatch may seem as a good idea, but you will still need dynamic casting somewhere when using them.
You can replace those two patterns using templates, but as soon as you'll get a vector of the base objects, you'll still have to dynamic_cast at some point.
I didn't measure this whatsoever, but I'm really interested in performance comparison of using virtual functions and dynamic cast as I imagine they'd be very similar...
End note:
Please notice, that I personally feel that using methods like equals or operator== on classes defining the basic interface is not very wise, since there are two possible outcomes:
The equals is virtual -> slow but acceptable
The equals is not virtual -> cannot be used in inherited types to actually do more advanced/relevant comparison, breaking the idea of Open to extension, closed for modification
Obviously, if you don't define the equals, you'd have to write comparison code every time. Or possibly use some templated Comparison class with possible specializations through traits yielding again the best performance with no code duplicity.
Generally speaking, you can get to point where you'd ask yourself "why isn't there base object and reflection like in java or c# in c++? It would allow me to use all these nice and clever patterns." The answer is templates. Why do it run-time, when you can do it compile time?
I'm not happy with the question title, but I couldn't describe it well. I'm putting implementation in the class declarations for sake of brevity.
I have a class like this:
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<sf::Shape> shape;
}
sf::Shape is an abstract class. Then I have a derived class like so:
class Brick : VisibleObject {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
std::dynamic_pointer_cast<sf::RectangleShape>(shapes).get()->setSize(newSize);
}
}
sf::RectangleShape() is a concrete class that inherits from sf::Shape and setSize() is defined for it, not sf::Shape, which is why I need to cast.
Of course, I need to do some error handling, in the case that the dynamic cast fails and returns an empty shared_ptr.
I'm doing this because I wanted to be able to define the draw method just once, since in this simple game, every object will draw their member this way. Originally I left the shape out of the base class, and e.g. Brick would just have its own private sf::RectangleShape that could get instantiated on the stack; which was clean, but then the draw method had to be re-written for each object type.
This works, but is uglier to work with and introduces heap allocation. I also have shared_ptr overhead (I would have used unique_ptr, but I needed dynamic casting).
Is this the most appropriate way of doing what I'm trying to do?
It might be preferable to keep the interface an interface, and not start mandating implementation details. So just have an empty base class like so:
class VisibleObject
{
public:
~VisibleObject() {}
virtual void draw(sf::RenderWindow & window) = 0;
virtual void setSize(sf::Vector2f const & size) = 0;
};
You can stick the shape storage into the concrete class that implements this interface.
Moreover, Shape should provide a virtual resize method:
class Shape
{
public:
virtual ~Shape() {}
virtual void resize(sf::Vector2f const & size) = 0;
};
Now you can make, say, a VisibleShapeObject as an intermediate base class:
class VisibleShapeObject : public VisibleObject
{
public:
virtual void draw(sf::RenderWindow & window) override final
{
window.draw(*shape_);
}
virtual void setSize(sf::Vector2f const & size) override final
{
shape_->resize(size);
}
protected:
std::shared_ptr<Shape> shape_; // or unique_ptr<Shape>
};
Instead of mandating storage in std::shared_ptr<sf::Shape>, why not simply introduce a means of retrieving an sf::Shape& from the concrete class?
class VisibleObject {
virtual sf::Shape& getShape() = 0;
public:
void draw(sf::RenderWindow& rw) {
rw.draw(getShape());
}
virtual void setSize(sf::Vector2f) = 0;
};
class Brick : VisibleObject {
sf::RectangleShape shape;
sf::Shape& getShape() override { return shape; }
public:
void setSize(sf::Vector2f newSize) override {
shape.setSize(newSize);
}
};
It seems ridiculous to store via a pointer to base, introducing indirections and downcasts and reference count overhead, when you could just store a plain old member. In fact, if I'm understanding the problem correctly, you could probably use a template to generate concrete classes and avoid a lot of boilerplate:
class VisibleObject {
public:
virtual ~VisibleObject() {}
virtual void draw(sf::RenderWindow&) = 0;
virtual void setSize(sf::Vector2f) = 0;
};
template <typename Shape>
class VisibleConcreteObject : public VisibleObject {
Shape shape;
public:
void draw(sf::RenderWindow& rw) override /* final? */ {
rw.draw(shape);
}
void setSize(sf::Vector2f newSize) override /* final? */ {
shape.setSize(newSize);
}
};
typedef VisibleConcreteObject<sf::RectangleShape> Brick;
You haven't shared everything you are trying to do, but this it one way:
template<ShapeT>
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<ShapeT> shape;
void reset(ShapeT* shape) {
this->shape = shape;
}
}
class Brick : VisibleObject<sf::RectangleShape> {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
shape->setSize(newSize);
}
}
There may be reasons why this doesn't work for you, but without more insight, I couldn't guess at what.
I'm developing a chess game. So, I created an abstract class called Piece and the real pieces implement this class, So I have concrete classes like Pawn, Rook...
The problem is: I need an equal method in the interface to compare two pieces. I'm having problem to it, because I wanted a polimorfic method, that is, a method that could compare a piece to any piece. The problem is I can't declare "Piece o" as an argument to the method cause Piece is an abstract type. How can I do this in C++?
I have the following code:
class Piece
{
public:
virtual ~Piece();
virtual std::string name() = 0;
virtual Color color() const = 0;
virtual Type type() const = 0;
virtual Position position() const = 0;
virtual void moveToPosition(Position p) = 0;
virtual bool isValidMove(Position np, Board &b) = 0;
virtual vector<Movimento>& generateMoves(Board &t) = 0;
virtual bool equal(Piece &o) = 0;
};
maybe do something like
virtual bool operator==(const Piece&) = 0;
no object slicing, u can compare the type and other information..
or you can just implement it in your Piece class, such as
virtual bool operator==(const Piece& rhs) {
if (this.type() == rhs.type()) {
return true;
}
else {
return false;
}
}
actually, you probably don't need operator== overloaded, but instead just a equal method...
I solved my problem changing the defition of Piece to an Abstract class instead of a Interface (in the Java vocabulary). Now my code is less redundant and clearer.
class Piece
{
protected:
std::string m_Name;
Color m_Color;
PieceType m_PieceType;
Position m_Position;
public:
Piece(std::string n, Color c, PieceType t, Position p) :
m_Name(n), m_Color(c), m_PieceType(t), m_Position(p){};
virtual ~Piece();
std::string name() const;
Color color() const;
PieceType pieceType() const;
Position position() const;
bool equal(const Piece&) const;
virtual void moveToPosition(Position p) = 0;
virtual bool isValidMove(Position np, Board &t) = 0;
virtual vector<Move>& generateMoves(Board *b) = 0;
};
I need to store a polymorphic object (let's say Polygon) inside another object (let's say Simulation). At the same time I want to keep encapsulation of Simulation.
class Polygon {
public:
virtual double area() { return 0; }
};
class Square : public Polygon {
public:
Square(double edge) : edge_(edge) {}
virtual double area() { return edge_*edge_; }
private:
double edge_;
};
class Simulation {
public:
Simulation(Polygon& polygon) { polygon_ = &polygon; }
Polygon* polygon() { return polygon_; }
private:
Polygon* polygon_;
};
int main (int argc, const char * argv[]) {
Square square(2.0);
Simulation sim(square);
std::cout<<sim.polygon()->area()<<"\n";
return 0;
}
This works perfectly fine! However, it violates encapsulation of Simulation, in fact, if from the main I go and change square it will also change inside Simulation.
I was thinking of modifying the constructor of Simulation using the copy constructor as:
Simulation(Polygon& polygon) { polygon_ = new Polygon(polygon); }
but this will mean that I don't have polymorphism...
There is obviously something I am missing here... CHEERS!
Add a clone function to Polygon (and a virtual destructor!). It is a good idea to ensure that Polygon is abstract so make sure at least one function is pure virtual.
Your Simulation class will require a copy constructor, destructor and assignment operator.
Note that the Square clone function can return a Square* even though the super class returns a Polygon* because it is covariant. Some older compilers may not support this, in which case return a Polygon*.
class Polygon {
public:
virtual ~Polygon() = 0;
virtual Polygon* clone() const = 0;
virtual double area() { return 0; }
};
inline Polygon::~Polygon() {}
class Square : public Polygon {
public:
Square(double edge) : edge_(edge) {}
virtual Square* clone() const { return new Square(*this); }
virtual double area() { return edge_*edge_; }
private:
double edge_;
};
class Simulation {
public:
Simulation(Polygon const& polygon)
: polygon_(polygon.clone())
{}
Simulation(Simulation const& rhs)
: polygon_(rhs.polygon_->clone())
{}
Simulation& operator=(Simulation const& rhs)
{
if (this != &rhs) {
delete polygon_;
polygon_ = rhs.polygon_->clone();
}
return *this;
}
~Simulation() {
delete polygon_;
}
Polygon* polygon() { return polygon_; }
private:
Polygon* polygon_;
};
If Simulation contains Polygon then it means that it is meant to do something with it. If you need to access the polygon directly from the 'outside', you have either missed the design somewhere, or if not, you can use observer pattern and have polygon notify the simulation if something about it changes.
So, either:
outside -> polygon -> callback -> simulation
or
outside -> simulation -> polygon
So you want to make sure that there's no way for outside code to alter the inner polygon of simulation, but yet allow any subclass to be used inside it? I.e. make sure that there are no references outside of simulation to the object passed by ref in the c'tor?
You could think of an abstract copy method to accomplish that: (don't forget to delete in simulation destructor)
class Polygon {
public:
virtual Polygon *copy() = 0;
//..
};
class Square : public Polygon {
public:
virtual Polygon *copy() { return new Square(_edge); }
//...
}
class Simulation {
public:
Simulation(const Polygon &p) : poly(p.copy()) {}
};
If you want to copy a polymorphic object, this can be done with a clone method.
class Polygon
{
...
virtual Polygon* clone() const = 0;
};
class Square: public Polygon
{
...
virtual Square* clone() const { return new Square(*this); }
};
However, in the example it seems a bit pointless that the Simulation neither does anything with the polygon itself nor do you want to hand it out for other code to use.
That's just how C++ works. If you write a wrapper for an object (PIMPL) you have to implement its full interface. The functions going to be very small just passing the calls to the actual implementation but you have to write them. Then you can alter the behaviour, add logging, or whatever you need...
You just need to decide if the polygon is inside or outside of simulation. If it's supposed to be outside of it, then you have reference constructor parameter . If it's inside, you'll need the following code:
class Simulation {
public:
Simulation() : poly(2.0) { }
Polygon *polygon() { return &poly; }
private:
Square poly;
};
Now, the polymorphism aspect you can easily do like this:
class Simulation {
public:
Simulation() : poly(2.0), poly2(3.0) { }
Polygon *polygon(int i)
{
switch(i) {
case 0: return &poly;
case 1: return &poly2;
}
return 0;
}
private:
Square poly;
Cylinder poly2;
};
And once you get tired to adding new data members, here's another trick which will fix some cases:
class Simulation {
public:
Simulation() : poly(2.0) { }
Polygon *polygon(float x)
{
poly.edge_ = x;
return &poly;
}
private:
Square poly;
};
Edit: Note that the order of classes in header file needs to be carefully considered.