Downcast from a container of Base* to Derived* without explicit conversion - c++

I am writing a scientific code which needs to create 3-dimensional cells, defined by a set of faces, which are defined by a set of vertices.
These 3 classes (Cell, Face, Vertex) are derived respectively from some generic geometry classes (Polyhedron, Polygon, Point) which implement some geometric routines like Polygon::CalculateArea().
The Face class adds to the Polygon class with additional data and functions required for the science, like Face::Interpolate(). I don't want to make these member functions virtual in the base class (Polygon).
Now, the problem. I initialize a Cell with a vector of pointers to Face, which is handled by the base class Polyhedron constructor, which upcasts the Face* to Polygon*:
Polyhedron::Polyhedron( std::initializer_list<Polygon*> polygons );
Later, I want to access the Face* stored in a Cell so that I can call Face::Interpolate(), but it has been stored as a Polygon* and thus has no member function Polygon::Interpolate(). I can downcast it manually back to a Face* which works, but is not very clean. The user of the code has to do something like:
Face * temp_face = (Face*)cell->GetFaces()[0]; // Could use static_cast
temp_face->Interpolate();
which is not obvious.
I want the interface to be transparent, so that this just works:
cell->GetFaces()[0]->Interpolate();
I can think of two or three ways to achieve this. I'm looking for a better solution or feedback of which of these is recommended:
In Cell::GetFaces() which currently just inherits from Polyhedron::GetPolygons() I could create a wrapper that copies the std::vector<Polygon*> to a new vector std::vector<Face*>. This seems sloppy to me, not easy to maintain, inefficient and prone to errors.
Instead of storing std::vector<Polygon*> I could store std::vector<std::shared_ptr<Polygon>>. From what I understand, these smart pointers retain type-awareness so that they can call the right destructor, but they might just store a reference to the destructor depending on implementation. I don't want to use shared_ptr for performance purposes -- I know they're good and friendly, but I'm creating millions of these Polygons and its easy to destroy them in the right place. I can't use unique_ptr easily because of the copy-constructor used in std::initializer_list constructors.
Template the whole Polyhedron class, replacing every instance of Polygon* with F* and checking that F is a base of Polygon:
template<typename F = Polygon>
typename std::enable_if<std::is_base_of<Polygon, F>::value, void>::type
class Polyhedron
and then inheriting from a parent with a given typename:
class Cell : public Polyhedron<Face>
This seems like the best method to me, since it has the least boilerplate and nothing exposed to the user; but it still feels messy, especially in the "real" case where there might be multiple types that would all have to be specified:
class Cell: public Polyhedron<Face,Vertex,type3,type4,type5,...>
Is there a a better way? Perhaps a means of retaining type in the original vector (or some other container)?
If not, which of the above methods is the best practice and why?
Edit:
Here's an abstracted view of the problem. The problem occurs when trying to run sumOfSomethingSpecific(). In my actual problem, that function is inside a derived class Derived_B, which is designed to work with Derived_A, but for the sake of the problem, it makes no difference.
class Base_A
{
public:
Base_A();
~Base_A();
// I don't want virtual doSomethingSpecific() here.
};
class Derived_A
{
public:
using Base_A::Base_A;
double doSomethingSpecific();
};
// I could template this whole class
// template <typename T>
// where T replaces Base_A
class B
{
public:
// This can be initialized with:
// std::vector<Derived_A*>
// which is what I want to do, but we lose info about doSomethingSpecific()
// even if I write a separate constructor its still stored as
// std::vector<Base_A*>
B(std::vector<Base_A*> v) : v(v) {};
~B();
double sumOfSomethingSpecific()
{
double sum = 0;
for(auto&& A : v) {
// Can't do this, A is a pointer of type Base_A*, but this is the abstraction that I want to achieve
sum += A->doSomethingSpecific();
// Could do this, but its ugly and error-prone
Derived_A* tempA = (Derived_A*)A;
sum += tempA->doSomethingSpecific();
}
return sum;
}
protected:
std::vector<Base_A*> v;
};

First most of issues you're facing here are not about programming, are about design.
... class with additional data and functions required for the science, like Face::Interpolate(). I don't want to make these member functions virtual in the base class (Polygon). ...
Well, don't do that, but then you have to realize that you're adding complexity to the code you need to implement such design desicion.
However, if every polygon can be "interpolated" then you should have a virtual function (or better yet a pure virtual function) in your Polygon class.
Said that, with the code as it is, in order to add transparency to the API you declare you get_* functions as:
void GetFaces(std::vector<Face *> &faces);
that way is clear for the user that he/she has to provide a reference to a vector of faces to get the result. Lets see how this change your code:
// Face * temp_face = (Face*)cell->GetFaces()[0]; // Could use static_cast
std::vector<Face *> temp_faces;
cell->GetFaces(temp_faces);
//temp_face->Interpolate();
temp_faces[0]->Interpolate();
This way the down-cast is performed implicitly.
About your question: Is there a a better way? Yes, redesign your classes.
About your example:
I will ask you to think a moment about this:
struct Base {};
struct Derived_A: Base { double doSomethingSpecific(); };
struct Derived_B: Base { double doSomethingSpecific(); };
int main()
{
std::vector<Base*> base_v = {/*suppose initialization here*/};
base_v[0]->doSomethingSpecific(); // Which function must be called here?
// Derived_A::doSomethingSpecific or
// Derived_B::doSomethingSpecific.
}
At some point you will have to tell wich type you want call the function on.
The level of abstraction you want, does not exists in C++. The compiler needs to know the type of an object in order to perform (compile) a call to one of its member functions.
Another approach you can try (I still recommend to redesign):
If you have the need of manipulating several distinct types in a uniform manner. Perhaps you want to take a look at Boot.Variant library.

I struggled with a similar problem in one of my projects. The solution I used was to give ownership of the actual objects to the most-derived class, give the base class a copy of the objects, and use a virtual function to keep the copy up-to-date as objects are added/removed:
class Polyhedron {
protected:
bool _polygons_valid = false;
std::vector<Polygon*> _polygons;
virtual void RebuildPolygons() = 0;
public:
std::vector<Polygon*>& GetPolygons()
{
if (!_polygons_valid) {
RebuildPolygons();
_polygons_valid = true;
}
return _polygons;
}
/*Call 'GetPolygons()' whenever you need access to the list of polygons in base class*/
};
class Cell: public Polyhedron {
private:
std::vector<Face*> _faces; //Remember to set _polygons_valid = false when modifying the _faces vector.
public:
Cell(std::initializer_list<Face*> faces):
_faces(faces) {}
//Reimplement RebuildPolygons()
void RebuildPolygons() override
{
_polygons.clear();
for (Face* face : _faces)
_polygons.push_back(face);
}
};
This design has the benefits of clear ownership (most-derived class is owner), and that copying and upcasting the vector of object pointers is done only when needed. The downside is that you have two copies of essentially the same thing; a vector of pointers to objects. The design is very flexible too, since any class derived from Polyhedron only has to implement the RebuildPolygons() function, using a vector of any type derived from Polygon.

Related

Comparing types between derived classes

I am making the engine for a game and I can't seem to solve the following problem.
So, I have a base component class from which all the different components are derived. A GameObject is basically a container for different components. The components are stored in a vector containing pointers to the base component class. Now I need the GameObject class to have a getComponent member function template that will return the component with the requested type from the vector.
To be more clear:
class Component
{
/..../
};
class RigidBody : Component
{
/..../
};
class Animation : Component
{
/..../
};
class GameObject
{
public:
template <class T>
T* getComponent();
void addComponent(Component*);
private:
std::vector<Component*> m_components;
};
/...../
GameObject test;
test.AddComponent(new RigidBody());
test.AddComponent(new Animation());
Animation * animation = test.getComponent<Animation>();
Or something among those lines.
For simplicity's sake say that the vector is guaranteed to have the component that we are looking for and that there are no components of the same type.
Since the pointers in the vector are of the base component type, how can I check if they originally were of the requested type? Thanks in advance!
Assuming that Component has at least one virtual function (otherwise what's the point of inheriting from it, right?) you should be able to do what you need using Runtime Type Information (RTTI) and dynamic_cast, like this:
template <class T> T* getFirstComponent() {
for (int i = 0 ; i != m_components.size() ; i++) {
T *candidate = dynamic_cast<T*>(m_components[i]);
if (candidate) {
return candidate;
}
}
return nullptr;
}
Recall that dynamic_cast<T*> would return a non-null value only when the cast has been successful. The code above goes through all pointers, and picks the first one for which dynamic_cast<T*> succeeds.
Important note: While this should do the trick at making your program do what you want, consider changing your design: rather than pulling out objects by type, give them virtual functions that would let you use them all in a uniform way. It is pointless to put objects of different classes into one container, only to pull them apart at some later time. RTTI should be used as the last resort, not as a mainstream tool, because it makes your program harder to understand.
Another valid approach would be to store the individual components separately, not in a single vector, and get the vector only when you need to treat the objects uniformly.
Less important note: if nullptr does not compile on your system, replace with return 0.
There are occasions where a system would want to group derived types from a base class vector, for example, the optimisation of multithreading.
One system I cooked up uses polymorphism to create a user defined type to avoid typeid or derived_class, here is some pseudo code...
class BaseType {
public:
virtual int getType() = 0;
}
class ThisType : public BaseType {
public:
int getType() {return 1;};
}
class TypeMaster {
private:
std::vector<ThisType*> myObjects;
public:
void add(ThisType* bc){ myObjects.push_back(bc); };
}
std::map<int,TypeMaster*> masters;
std::vector<BaseType*> objects;
for(int i=0;i<objects.size();i++){
masters.find(objects[i].getType())->second.add(objects[i]);
}
You would have to do a bit of work to make a system but the rudements are there to convey the idea. This code processes an arbitary vector of base objects and appends them to the vector of its type master.
My example has a collection of execution pools with multiple instances of the type master meaning the type master cannot be polymorphed because in that scenario the object would not be able to move around execution pools.
Note the lack of use of typeid or derived class. For me, implementations using native types keeps it simple without importing bloating libraries or any unnecessary execution fuss. You could perform speed trials but I have always found simple native type implementations to be quite succinct.

"Addition" of two classes

I've been doing some dynamical system simulations in a rather crude functional way and am currently trying to figure out what can cpp objects bring to my code. More specifically, I was thinking about the following construction:
I would like to specify the dynamical system by an abstract class, say "DynSys", with a purely virtual method specifying the dynamics (say "energy" and others). Once I derive two concrete classes from DynSys, I would like to do a "superposition" of their instances in the sense of creation of a new DynSys object that returns an addition of the two respective dynamical member functions. Is this possible? E.G.:
DynamicHole Blackhole; // DynSys derived
DynamicDisc Disc; // DynSys as well
vector state; // eg a dynamical array of numbers
Blackhole.energy(state); // returns A(state)
Disc.energy(state); // returns B(state)
??class?? HoleDisc = DynamicAddition(&Blackhole,&Disc); // is a DynSys
HoleDisc.energy(state); // returns A(state)+B(state)
The pointer to a DynSys object is passed to the simulation itself, so it is important for the result to be a DynSys object.
I saw some constructions using the "+" operator or befriending to add the parameters of the class. However, the problem here seems to be the fact that the addition process involving method addition would need to define a completely new concrete class.
I see a rather inelegant workaround by defining the "core" functions A(state,parameters), B(state,parameters) separately and then defining the superposition class by hand. I have quite a lot of superpositions to make, so I wondered whether there was a better way to do this.
If I understand correctly, when you "add" to DynSys together you want to create some aggregation. Here is a pseudocode that could be adapted to your needs:
class DynSysGroup : public DynSys
{
DynSys& m_a;
DynSys& m_b;
public:
DynSysGroup(DynSys& a, DynSys& b) : m_a(a), m_b(b) { }
// I'm guessing the signature of energy()...
void energy(vector& v)
{
// Get A(state) with m_a
// Get B(state) with m_b
// Do A(state) + B(state)
}
}
And your line above
??class?? HoleDisc = DynamicAddition(&Blackhole,&Disc); // is a DynSys
would become
DynSysGroup HoleDisc(Blackhole, Disc);
Of course, with reference like m_a and m_b you need to make sure you don't get dangling reference. Maybe you'll need to use smart pointers like std::shared_ptr.
Side note: you may want to look into std::valarray and change the way energy() works: instead of taking a vector as parameter, you could simply return it (it if fits your design, of course).
std::valarray DynSys::energy() const { return ...; }

About implementation of abstract/concrete graphs in C++

I am writing a program that works with graphs. I am dealing with two types of graphs : "abstract graphs", which consist in abstract vertices with edges, and "planar graphs", in which the vertices have coordinates x,y in the plane (actually I am working with a complex affix z but it does not matter).
I have elected to write an (abstract) Vertex class and a derived class Planar_Vertex as follows in my Vertex.h file - this is not precisely my code, I made it slightly simpler and "translated" it from French ;)
class Vertex
{
public:
Vertex();
int get_label();
void set_label(int label);
void add_neighbor(int label);
bool is_neighbor(int label);
// etc
protected:
int _label;
std::vector<int> _list_neighbors;
};
class Planar_Vertex : public Vertex
{
complex<double> _affix;
public:
Planar_Vertex();
Planar_Vertex(Vertex& V, complex<double> affix);
complex<double> get_affix();
void set_affix(complex<double> affix);
};
Here's my main question. I would like my Planar_Vertex(Vertex& V, complex affix) constructor to have the following effects : 1. Output a Planar_Vertex whose label and list of neighbors are the same as V, and whose affix is given. So far, easy. 2. I would like V to be precisely the abstract Vertex underlying this new object. In other words, if in my main.cpp file I wrote, say,
Vertex V1;
...
Planar_Vertex V2(V1,z)
then I would like that a use of set_label() on V2 will also affect V1 (for example). The way I see it is, in this constructor, I would like to say something like: make the address of V (in memory) the same as that of the Planar_Vertex constructed (and free the memory previously allocated to V). Apparently it is not possible to change the location of a variable in memory though, so I don't know what to do. I am relatively new to C++ and I'm getting lost reading about placement new, std::move, rvalues etc. Does anybody see how to do what I want?
[Edit : To summarize, I want to be able to build an object of the derived class on top of an object of the base class that has already been built.]
Okay, now since I told you guys that much about my implementation of graphs, I thought I'd tell you the rest so you can give me your opinion about it, I hope you don't mind. Obviously you don't have to read the following, if you know the answer to my first question that'd be cool already. So as I told you we're dealing with "abstract graphs", which will consist in abstract vertices, and planar graphs, which consist in planar vertices.
Here's what my Graph.h file looks like:
class Graph
{
public:
Graph();
virtual ~Graph();
virtual std::vector<Vertex*> get_list_vertices();
void add_edge(int label1, int label2);
virtual void add_vertex(Vertex&);
// etc
};
class Abstract_Graph : public Graph
{
std::vector<Vertex*> _list_vertices;
public:
Abstract_Graph();
~Abstract_Graph();
std::vector<Vertex*> get_list_vertices();
void add_vertex(Vertex& V);
// etc
};
class Planar_Graph : public Graph
{
std::vector<Planar_Vertex*> _list_planar_vertices;
public:
Planar_Graph();
~Planar_Graph();
std::vector<Vertex*> get_list_vertices();
std::vector<Planar_Vertex*> get_list_planar_vertices();
void add_vertex(Planar_Vertex& V);
// etc
};
My idea is that the base class Graph will never be instanciated, but I will be able to implement "abstract graph operations" as functions of this base class and they will work on both Abstract_Graph and Planar_Graph objects. This is made possible thanks to the purely virtual function get_list_vertices. Is this a reasonable way to do things? What would you have done?
Thank you very much for for answers in advance.
You can keep a reference (or a pointer) to a Vertex object in your Planar_Vertex class to do what you want if I understood you.
Cut down demo:
#include <iostream>
struct Vertex {
int value;
};
struct Planar_Vertex: public Vertex {
Vertex& vr;
Planar_Vertex(Vertex& v): vr(v) {}
};
int main()
{
Vertex v;
v.value = 1;
std::cout << v.value << std::endl;
Planar_Vertex p = Planar_Vertex(v);
p.vr.value = 2;
std::cout << v.value << std::endl;
}
If you use a reference, it must be initialized in the constructor initialization list. If you use a pointer, you have more flexibility in how you initialize it, but have to worry about null pointers everywhere.
In both cases, you're responsible for making sure that the Vertex outlives the Planar_Vertex.
(Another option is to have a plain Vertex (not a reference or pointer) as a member of Planar_Vertex – you initialize it via Planar_Vertex's constructor, and use it wherever you need. This takes care of the lifetime requirements, but might not be possible in your code.)
For your second part, I don't see anything fundamentally wrong, but it's hard to have an opinion just with what you posted. Inheritance is one way to do this, another would be to use templates. Which one is more appropriate depends on the exact requirements (and your familiarity with both these concepts).

How should I design a set of related classed where only some of them support a certain operation?

I am working on a slide-based application in C++.
Each slide has a slide-items collection which can
include items like caption, button, rectangle, etc.
Only some of these items support fill, while others
don't.
What is the best way to implement the fill for the slide items in this case?
Here are two ways that I thought of:
Create an interface Fillable and implement this interface for slide items
which support fill, keeping all the properties related to fill in the interface. When iterating over the list of slide items, dynamic_cast them
into Fillable, and if successful, do the operation related to fill.
Make a fill class. Make a fill pointer a part of slide item class, assign the
fill object to the fill pointer for those objects which support fill, and for rest of them keep it null. Give a function GetFill, which will return the fill for the items if it exists otherwise returns NULL.
What's the best approach for this? I'm interested in performance and maintainability.
I would do a combination of the two. Make your Fillable interface and have it be the return type for your GetFill method. This is better than the dynamic cast approach. Using dynamic cast to query for the interface requires that the actual slide item object implement the interface if it is to support it. With an accessor method like GetFill however, you have the option of providing a reference/pointer to some other object that implements the interface. You can also just return this if the interface is in fact implemented by this object. This flexibility can help avoid class bloat and promote the creation of re-usable component objects that can be shared by multiple classes.
Edit:
This approach also works nicely with the null object pattern. Instead of returning a null pointer for the objects that don't support Fillable, you can return a simple no-op object that implements the interface. Then you don't have to worry about always checking for null pointers in the client code.
The answer is it depends.
I don't see the point in having to clutter your base interface with fill/get_fillable_instance/... if not every object is supposed to handle fill. You can however get away with just
struct slide_object
{
virtual void fill() {} // default is to do nothing
};
but it depends on whether you think fill should appear in the slide object abstract class. It rarely should however, unless being non fillable is exceptional.
Dynamic casting can be correct in the case you need to provide two distinct classes of objects (and no more than two), some of them being fillable, and the other having nothing to do with fillability. In this case, it makes sense to have two sub-hierarchies and use dynamic casting where you need.
I have used this approach successfully in some cases and it is simple and maintainable, provided the dispatch logic is not scattered (ie. there is only one or two places where you dynamic cast).
If you are expected to have more fill-like behavior, then dynamic_cast is a wrong choice since it will lead to
if (auto* p = dynamic_cast<fillable*>(x))
...
else if (auto* p = dynamic_cast<quxable*>(x))
...
which is bad. If you are going to need this, then implement a Visitor pattern.
Create a base class SlideItem:
class SlideItem {
public:
virtual ~SlideItem();
virtual void fill() = 0;
};
Then do an empty implementation for those you can't fill:
class Button : public SlideItem {
public:
void fill() { }
};
And a proper fill implementation for the others:
class Rectangle : public SlideItem {
public:
void fill() { /* ... fill stuff ... */ }
};
and put all of them inside a container.. if you want to fill them just call everybody... easy to maintain.. and who cares about performance :)
If you really need fast code your first solution is certainly good. But if you do it like that, make sure you don't have to cast it every time you want to fill. Cast them one time and put the pointers in a fillable-container. Then iterate over this fillable-container if you have to fill.
Then again, IMHO you put too much effort into this, without a reasonable performance gain. (of course I don't know your application, it might be justified.. but usually not)
It seems like what you're looking for is close to the Capability Pattern. Your #2 is close to this pattern. Here's what I would do:
Make a fill class. Make fill pointer a part of slide item class, assign the fill object to fill pointer for only those objects which support fill, for rest of them keep it null. Create a function GetCapability(Capability.Fill), which will return the fill for the items if it exists otherwise returns NULL. If some of your objects already implement a Fillable interface, then you can return the object cast to a Fillable pointer instead.
Consider storing Variant items, such as boost::variant.
You can define a boost::variant<Fillable*,Item*> (you should use smart pointers if you have ownership), and then have a list of those variants on which to iterate.
I suggest using an interface for the shapes, with a method that returns a filler. For example:
class IFiller {
public:
virtual void Fill() = 0;
protected:
IFiller() {}
virtual ~IFiller() {}
};
class IShape {
public:
virtual IFiller* GetFiller() = 0;
protected:
IShape() {}
virtual ~IShape() {}
};
class NullFiller : public IFiller {
public:
void Fill() { /* Do nothing */ }
};
class Text : public IShape {
public:
IFiller* GetFiller() { return new NullFiller(); }
};
class Rectangle;
class RectangleFiller : public IFiller {
public:
RectangleFiller(Rectangle* rectangle) { _rectangle = rectangle; }
~RectangleFiller() {}
void Fill() { /* Fill rectangle space */ }
private:
Rectangle* _rectangle;
};
class Rectangle : IShape {
public:
IFiller* GetFiller() { return new RectangleFiller(this); }
};
I find this method easier to maintain and to extend, while it does not introduce major performance issues.

Best Practice For List of Polymorphic Objects in C++

What is a common practice for the storage of a list of base class pointers each of which can describe a polymorphic derived class?
To elaborate and in the interest of a simple example lets assume that I have a set of classes with the following goals:
An abstract base class whose purpose is to enforce a common functionality on its derived classes.
A set of derived classes which: can perform a common functionality, are inherently copyable (this is important), and are serializable.
Now alongside this required functionality I want to address the following key points:
I want the use of this system to be safe; I don't want a user to have undefined errors when he/she erroneously casts a base class pointer to the wrong derived type.
Additionally I want as much as possible the work for copying/serializing this list to be taken care of automatically. The reason for this is, as a new derived type is added I don't want to have to search through many source files and make sure everything will be compatible.
The following code demonstrates a simple case of this, and my proposed (again I am looking for a common well thought out method of doing this, mine may not be so good) solution.
class Shape {
public:
virtual void draw() const = 0;
virtual void serialize();
protected:
int shapeType;
};
class Square : public Shape
{
public:
void draw const; // draw code here.
void serialize(); // serialization here.
private:
// square member variables.
};
class Circle : public Shape
{
public:
void draw const; // draw code here.
void serialize(); // serialization here.
private:
// circle member variables.
};
// The proposed solution: rather than store list<shape*>, store a generic shape type which
// takes care of copying, saving, loading and throws errors when erroneous casting is done.
class GenericShape
{
public:
GenericShape( const Square& shape );
GenericShape( const Circle& shape );
~GenericShape();
operator const Square& (); // Throw error here if a circle tries to get a square!
operator const Circle& (); // Throw error here if a square tries to get a circle!
private:
Shape* copyShape( const Shape* otherShape );
Shape* m_pShape; // The internally stored pointer to a base type.
};
The above code is certainly missing some items, firstly the base class would have a single constructor requiring the type, the derived classes would internally call this during their construction. Additionally in the GenericShape class, copy/assignment constructor/operator would be present.
Sorry for the long post, trying to explain my intents fully. On that note, and to re-iterate: above is my solution, but this likely has some serious flaws and I would be happy to hear about them, and the other solutions out there!
Thank you
What is the problem of a std::list< shape* > (or a std::list< boost::shared_ptr > thereof)?
That would be the idiomatic way of implementing a list of shapes with polymorphic behavior.
I want the use of this system to be safe; I don't want a user to have undefined errors when he/she erroneously casts a base class pointer to the wrong derived type.
Users should not downcast, but rather use the polymorphism and the base (shape) operations provided. Consider why they would be interested in downcasting, if you find a reason to do so, go back to drawing board and redesign so that your base provides all needed operations.
Then if the user wants to downcast, they should use dynamic_cast, and they will get the same behavior you are trying to provide in your wrapper (either a null pointer if downcasting pointers or a std::bad_cast exception for reference downcasting).
Your solution adds a level of indirection and (with the provided interface) require the user to try guessing the type of shape before use. You offer two conversion operators to each of the derived classes, but the user must call them before trying to use the methods (that are no longer polymorphic).
Additionally I want as much as possible the work for copying/serializing this list to be taken care of automatically. The reason for this is, as a new derived type is added I don't want to have to search through many source files and make sure everything will be compatible.
Without dealing with deserialization (I will come back later), your solution, as compared to storing (smart) pointers in the list, requires revisiting the adapter to add new code for each and every other class that is added to the hierarchy.
Now the deserialization problem.
The proposed solution is using a plain std::list< boost::shared_ptr >, once you have the list built, drawing and serialization can be performed right out of the box:
class shape
{
public:
virtual void draw() = 0;
virtual void serialize( std::ostream& s ) = 0;
};
typedef std::list< boost::shared_ptr<shape> > shape_list;
void drawall( shape_list const & l )
{
std::for_each( l.begin(), l.end(), boost::bind( &shape::draw, _1 ));
}
void serialize( std::ostream& s, shape_list const & l )
{
std::for_each( l.begin(), l.end(), boost::bind( &shape::serialize, _1, s ) );
}
Where I have used boost::bind to reduce code bloat instead of iterating manually. The problem is that you cannot virtualize construction as before the object has been constructed you cannot know what type it actually is. After the problem of deserializing one element of a known hierarchy is solved, deserializing the list is trivial.
Solutions to this problem are never as clean and simple as the code above.
I will assume that you have defined unique shape type values for all shapes, and that your serialization starts by printing out that id. That is, the first element of serialization is the type id.
const int CIRCLE = ...;
class circle : public shape
{
// ...
public:
static circle* deserialize( std::istream & );
};
shape* shape_deserialize( std::istream & input )
{
int type;
input >> type;
switch ( type ) {
case CIRCLE:
return circle::deserialize( input );
break;
//...
default:
// manage error: unrecognized type
};
}
You can further alleviate the need to work on the deserializer function if you convert it into an abstract factory where upon creation of a new class the class itself registers it's deserialization method.
typedef shape* (*deserialization_method)( std::istream& );
typedef std::map< int, deserialization_method > deserializer_map;
class shape_deserializator
{
public:
void register_deserializator( int shape_type, deserialization_method method );
shape* deserialize( std::istream& );
private:
deserializer_map deserializers_;
};
shape* shape_deserializator::deserialize( std::istream & input )
{
int shape_type;
input >> shape_type;
deserializer_map::const_iterator s = deserializers_.find( shape_type );
if ( s == deserializers_.end() ) {
// input error: don't know how to deserialize the class
}
return *(s->second)( input ); // call the deserializer method
}
In real life, I would have used boost::function<> instead of the function pointers, making the code cleaner and clearer, but adding yet another dependency to the example code. This solution requires that during initialization (or at least before trying to deserialize) all classes register their respective methods in the shape_deserializator object.
You could avoid lots of repetition in GenericShape by using templates (for the constructors and converters), but the key bit that's missing is having it inherit from Shape and implement its virtuals -- without it it's unusable, with it it's a pretty normal variant on envelope/implementation idioms.
You may want to use auto_ptr (or somewhat-smarter pointers) rather than a bare pointer to Shape, too;-).
I would propose boost::shared_pointer<Shape> in an STL container. Then use dynamic_cast to downcast guarantee type correctness. If you want to provide helper functions to toss exceptions instead of returning NULL, then follow Alex's suggestion and define a template helper function like:
template <typename T, typename U>
T* downcast_to(U *inPtr) {
T* outPtr = dynamic_cast<T*>(inPtr);
if (outPtr == NULL) {
throw std::bad_cast("inappropriate cast");
}
return outPtr;
}
and use it like:
void some_function(Shape *shp) {
Circle *circ = downcast_to<Circle>(shp);
// ...
}
Using a separate class like GenericShape is just too strongly coupled with every class that descends from Shape. I wonder if this would be considered a code smell or not...
I want the use of this system to be
safe; I don't want a user to have
undefined errors when he/she
erroneously casts a base class pointer
to the wrong derived type.
Why would you get undefined errors? The behavior of dynamic_cast is perfectly well-defined and catches the error if you cast a base class pointer to the wrong derived type. This really seems like reinventing the wheel.
Additionally I want as much as
possible the work for
copying/serializing this list to be
taken care of automatically. The
reason for this is, as a new derived
type is added I don't want to have to
search through many source files and
make sure everything will be
compatible.
I'm not sure what the problem is here. If all the derived classes are serializable and copyable, isn't that good enough? What more do you need?
I'm also not sure what to make of the first two requirements.
What do you mean, the ABC should "enforce a common functionality"? And what is the point in having derived classes, if their role is only to perform that same common functionality, be copyable and serializable?
Why not just make one non-abstract class serializable and copyable then?
I'm probably missing something vital here, but I don't really think you've explained what it is you're trying to achieve.