Some times we have to put different objects in the same hierarchy in one container. I read some article saying there are some tricks and traps. However, I have no big picture about this question. Actually, this happens a lot in the real word.
For example, a parking lot has to contain different types of cars; a zoo has to contain different types of animals; a book store has to contain different types of books.
I remember that one article saying neither of the following is a good design, but I forgot where it is.
vector<vehicle> parking_lot;
vector<*vehicle> parking_lot;
Can anybody offer some basic rules for this kind of question?
I learnt a lot writing my reply to a similar question by the same author, so I couldn't resist to do the same here. In short, I've written a benchmark to compare the following approaches to the problem of storing heterogeneous elements in a standard container:
Make a class for each type of element and have them all inherit from a common base and store polymorphic base pointers in a std::vector<boost::shared_ptr<Base> >. This is probably the more general and flexible solution:
struct Shape {
...
};
struct Point : public Shape {
...
};
struct Circle : public Shape {
...
};
std::vector<boost::shared_ptr<Shape> > shapes;
shapes.push_back(new Point(...));
shapes.push_back(new Circle(...));
shapes.front()->draw(); // virtual call
Same as (1) but store the polymorphic pointers in a boost::ptr_vector<Base>. This is a bit less general because the elements are owned exclusively by the vector, but it should suffice most of the times. One advantage of boost::ptr_vector is that it has the interface of a std::vector<Base> (without the *), so its simpler to use.
boost::ptr_vector<Shape> shapes;
shapes.push_back(new Point(...));
shapes.push_back(new Circle(...));
shapes.front().draw(); // virtual call
Use a C union that can contain all possible elements and then use a std::vector<UnionType>. This is not very flexible as we need to know all element types in advance (they are hard-coded into the union) and also unions are well known for not interacting nicely with other C++ constructs (for example, the stored types can't have constructors).
struct Point {
...
};
struct Circle {
...
};
struct Shape {
enum Type { PointShape, CircleShape };
Type type;
union {
Point p;
Circle c;
} data;
};
std::vector<Shape> shapes;
Point p = { 1, 2 };
shapes.push_back(p);
if(shapes.front().type == Shape::PointShape)
draw_point(shapes.front());
Use a boost::variant that can contain all possible elements and then use a std::vector<Variant>. This is not very flexible like the union but the code to deal with it is much more elegant.
struct Point {
...
};
struct Circle {
...
};
typedef boost::variant<Point, Circle> Shape;
std::vector<Shape> shapes;
shapes.push_back(Point(1,2));
draw_visitor(shapes.front()); // use boost::static_visitor
Use boost::any (which can contain anything) and then a std::vector<boost::any>. That is very flexible but the interface is a little clumsy and error prone.
struct Point {
...
};
struct Circle {
...
};
typedef boost::any Shape;
std::vector<Shape> shapes;
shapes.push_back(Point(1,2));
if(shapes.front().type() == typeid(Point))
draw_point(shapes.front());
This is the code of the full benchmark program (doesn't run on codepad for some reason). And here are my performance results:
time with hierarchy and boost::shared_ptr: 0.491 microseconds
time with hierarchy and boost::ptr_vector: 0.249 microseconds
time with union: 0.043 microseconds
time with boost::variant: 0.043 microseconds
time with boost::any: 0.322 microseconds
My conclusions:
Use vector<shared_ptr<Base> > only if you need the flexibility provided by runtime polymorphism and if you need shared ownership. Otherwise you'll have significant overhead.
Use boost::ptr_vector<Base> if you need runtime polymorphism but don't care about shared ownership. It will be significantly faster than the shared_ptr counterpart and the interface will be more friendly (stored elements not presented like pointers).
Use boost::variant<A, B, C> if you don't need much flexibility (i.e. you have a small set of types which will not grow). It will be lighting fast and the code will be elegant.
Use boost::any if you need total flexibility (you want to store anything).
Don't use unions. If you really need speed then boost::variant is as fast.
Before I finish I want to mention that a vector of std::unique_ptr will be a good option when it becomes widely available (I think it's already in VS2010)
The problem with vector<vehicle> is that the object only holds vehicles. The problem with vector<vehicle*> is that you need to allocate and, more importantly, free the pointers appropriately.
This might be acceptable, depending on your project, etc...
However, one usually uses some kind of smart-ptr in the vector (vector<boost::shared_ptr<vehicle>> or Qt-something, or one of your own) that handles deallocation, but still permits storing different types objects in the same container.
Update
Some people have, in other answers/comments, also mentioned boost::ptr_vector. That works well as a container-of-ptr's too, and solves the memory deallocation problem by owning all the contained elements. I prefer vector<shared_ptr<T>> as I can then store objects all over the place, and move them using in and out of containers w/o issues. It's a more generic usage model that I've found is easier for me and others to grasp, and applies better to a larger set of problems.
The problems are:
You cannot place polymorphic objects into a container since they may differ in size --i.e., you must use a pointer.
Because of how containers work a normal pointer / auto pointer is not suitable.
The solution is :
Create a class hierarchy, and use at least one virtual function in your base class (if you can't think of any function to virtualize, virtualize the destructor -- which as Neil pointed out is generally a must).
Use a boost::shared_pointer (this will be in the next c++ standard) -- shared_ptr handles being copied around ad hoc, and containers may do this.
Build a class hierarchy and allocate your objects on the heap --i.e., by using new. The pointer to the base class must be encapsulated by a shared_ptr.
place the base class shared_pointer into your container of choice.
Once you understand the "whys and hows" of the points above look at the boost ptr_containers -- thanks to Manual for the tip.
Say vehicle is a base class, that has certain properties, then, inheriting from it you have say a car, and a truck. Then you can just do something like:
std::vector<vehicle *> parking_lot;
parking_lot.push_back(new car(x, y));
parking_lot.push_back(new truck(x1, y1));
This would be perfectly valid, and in fact very useful sometimes. The only requirement for this type of object handling is sane hierarchy of objects.
Other popular type of objects that can be used like that are e.g. people :) you see that in almost every programming book.
EDIT:
Of course that vector can be packed with boost::shared_ptr or std::tr1::shared_ptr instead of raw pointers for ease of memory management. And in fact that's something I would recommend to do by all means possible.
EDIT2:
I removed a not very relevant example, here's a new one:
Say you are to implement some kind of AV scanning functionality, and you have multiple scanning engines. So you implement some kind of engine management class, say scan_manager which can call bool scan(...) function of those. Then you make an engine interface, say engine. It would have a virtual bool scan(...) = 0; Then you make a few engines like my_super_engine and my_other_uber_engine, which both inherit from engine and implement scan(...). Then your engine manager would somewhere during initialization fill that std::vector<engine *> with instances of my_super_engine and my_other_uber_engine and use them by calling bool scan(...) on them either sequentially, or based on whatever types of scanning you'd like to perform. Obviously what those engines do in scan(...) remains unknown, the only interesting bit is that bool, so the manager can use them all in the same way without any modification.
Same can be applied to various game units, like scary_enemies and those would be orks, drunks and other unpleasant creatures. They all implement void attack_good_guys(...) and your evil_master would make many of them and call that method.
This is indeed a common practice, and I would hardly call it bad design for as long as all those types actually are related.
You can refer to this Stroustrup's answer to the question Why can't I assign a vector< Apple*> to a vector< Fruit*>?.
Related
I have a class Group containing a vector of objects of another class Entry. Inside the Group I need to frequently access the elements of this vector(either consequently and in random order). The Entry class can represent a data of two different types with the same properties(size, content, creation time etc.). So all of the members and methods of the Entry class are the same for both data types, except for one method, that should behave differently depending on the type of the data. It looks like this:
class Entry
{
public:
// ...
void someMethod();
// ...
private:
TYPE type_;
// ...
};
class Group
{
private:
// ...
std::vector<Entry> entries_;
// ...
};
void Entry::someMethod()
{
if (type_ == certainType)
{
// Do some stuff
}
else if (type_ == anotherType)
{
// Do some different stuff
}
}
Given the abilities of C++ regarding OOP, this approach seems unnatural to me. I am thinking about creation of two distinct classes inherited from the Entry class and overriding only this someMethod() in those classes:
class Entry
{
// ...
virtual void someMethod() = 0;
// ...
};
class EntryType1 : public Entry
{
// override someMethod() here
};
class EntryType2 : public Entry
{
// override someMethod() here
};
But doing so means reducing the efficiency of cache usage, because now inside the Group class I have to replace the vector of Entry objects placed in a contiguous memory area with the vector of pointers to Entry base class objects scattered all over the memory address space.
The question is - is it worth it to make a class polymorphic just because of one only among many other of its methods is needed to behave differently depending on the data type? Is there any better approach?
is it worth it to make a class polymorphic just because of one only among many other of its method is needed to behave differently depending on the data type?
Runtime polymorphism starts to provide undeniable net value when the class hierarchy is deep, or may grow arbitrarily in future. So, if this code is just used in the private implementation of a small library you're writing, start with what's more efficient if you have real reason to care about efficiency (type_ and if), then it's not much work to change it later anyway. If lots of client code may start to depend your choices here though, making it difficult to change later, and there's some prospect of further versions of someMethod() being needed, it's probably better to start with the virtual dispatch approach.
Is there any better approach?
Again - what's "better" takes shape at scale and depends on how the code is depended upon, updated etc.. Other possible approaches include using a std::variant<EntryType1, EntryType2>, or even a std::any object, function pointers....
If you are absolutely sure that there are only two types of Entry, then using an if inside the function's implementation is, to me, a perfectly valid approach. In this case, I would advise you to use if constexpr to further indicate that this is a compile-time behavioral decision and not a runtime one. (As pointed out by Tony Delroy, if constexpr is not viable).
If, however, you are unsure if you are going to need more Entry types in the future, the if approach would only hurt you in the long run. If you need the scalability, I would advise you to make the Entry class hold a std::function internally for only that specific behavior that needs polymorphism: this way you're only paying for indirection when you actually need the functionality.
You could also make two factory functions make_Entry1 and make_Entry2 that construct an Entry passing it the specific std::function that yields the desired behavior.
Using polymorphism in C++ usually requires dynamic allocation, use of the factory pattern, etc. Is that not a true statement? Sure, I can instantiate a derived type on the stack if I really try, but is that every day code or an academic exercise?
Some other object orientated languages allocate every user made type on the heap. However, any allocation in C++ us likely to raise debates over performance with your peers.
How then, are you to use polymorphism while keeping allocation to a minimum?
Also, are we really writing real world code while using polymorphism without any dynamic allocation? Are we to forget we ever learned the factory pattern?
Edit:
It seems to me in this Q&A that we have identified a difference between scenarios where the type is known at compile time or it isn't.
It has been brought up that the use of streams are an example of polymorphism without dynamic allocation. However, when you are using streams, you know the type you need as you are typing out your program.
On the other hand, there are the scenarios where you don't know the type at compile time. This is where I reach (and have been taught to reach) for the factory pattern. Given some input, decide what concrete type to instantiate. I don't see any alternative to this. Is there one?
--
Let's try to use a scenario that came up in real world code.
Let us assume a stock trading system.
Your job is to store orders that arrive over the network from customers.
Your input is JSON text.
Your output should be a collection of data structures representing the orders
An order could be a vanilla stock purchase, an Option, or a Future.
You do not know what customers are ordering until you parse the JSON
Naturally, I'd come up with something like this, super simplified for purposes of example, domain:
class Order
{
protected:
double m_price;
unsigned m_size;
};
class Option : public Order
{
protected:
string m_expirationDate;
};
class Future : public Order
{
protected:
string m_expirationDate;
};
And then I'd come up with some factory that parses the JSON and spits out an order:
class OrderFactory
{
Order * CreateOrder(const std::string & json);
};
The factory allocates. Therefore, your peers are likely to point out that it's slow in a system that receives millions of orders per second.
I suppose we could convert our domain to some C like monstrosity:
struct Order
{
enum OrderType
{
ORDER_TYPE_VANILLA,
ORDER_TYPE_OPTION,
ORDER_TYPE_FUTURE
}
OrderType m_type;
double m_price;
unsigned m_size;
std::string m_expirationDate; // empty means it isnt used
int m_callOrPut // Encoder rings are great for code!
// -1 - not used
// 0 - Put
// 1 - Call
};
but then we are just ditching polymorphism, and what I think are good OO principles, altogether. We'd still, most likely be allocating these and storing them as they came in too. Unless we want to declare some statically sized container for them and mark elements used or un-used....(yet more C)
Is there some alternative that would not allocate that I am not aware of?
Using polymorphism in C++ usually requires dynamic allocation, use of
the factory pattern, etc. Is that not a true statement? Sure, I can
instantiate a derived type on the stack if I really try, but is that
every day code or an academic exercise?
"Usually" is a bit meaningless; it's a fuzzy comparison on which there are no metrics to produce statistics. Is it possible to use polymorphism without dynamic allocation? Yes, trivially. Consider this case:
struct A{};
struct B : A;
void foo(A& a) {};
void foo(A* a) {};
void bar() {
B b;
foo(b);
foo(&b);
}
and no dynamic memory used.
First off, in C++ people often distinguish compile-time and run-time polymorphis, I take it, your question is about run-time polymorphic behavior.
Yes, there are ways to enjoy polymorphism without using dynamic allocation. A good example of such are streams in STL. (Although, a lot of people question their design, but that's beside the point).
There are people who say that unless you have a container of (pointers to) polymorphic objects of different dynamic types, run-time polymorphism is really not needed and templates would work better - but since templates comes at their own cost, sometimes run-time polymorphism is suited better.
I often read this statements on Stack Overflow. Personally, I don't find any problem with this, unless I am using it in a polymorphic way; i.e. where I have to use virtual destructor.
If I want to extend/add the functionality of a standard container then what is a better way than inheriting one? Wrapping those container inside a custom class requires much more effort and is still unclean.
There are a number of reasons why this a bad idea.
First, this is a bad idea because the standard containers do not have virtual destructors. You should never use something polymorphically that does not have virtual destructors, because you cannot guarantee cleanup in your derived class.
Basic rules for virtual dtors
Second, it is really bad design. And there are actually several reasons it is bad design. First, you should always extend the functionality of standard containers through algorithms that operate generically. This is a simple complexity reason - if you have to write an algorithm for every container it applies to and you have M containers and N algorithms, that is M x N methods you must write. If you write your algorithms generically, you have N algorithms only. So you get much more reuse.
It is also really bad design because you are breaking a good encapsulation by inheriting from the container. A good rule of thumb is: if you can perform what you need using the public interface of a type, make that new behavior external to the type. This improves encapsulation. If it's a new behavior you want to implement, make it a namespace scope function (like the algorithms). If you have a new invariant to impose, use containment in a class.
A classic description of encapsulation
Finally, in general, you should never think about inheritance as a means to extend the behavior of a class. This is one of the big, bad lies of early OOP theory that came about due to unclear thinking about reuse, and it continues to be taught and promoted to this day even though there is a clear theory why it is bad. When you use inheritance to extend behavior, you are tying that extended behavior to your interface contract in a way that ties users hands to future changes. For instance, say you have a class of type Socket that communicates using the TCP protocol and you extend it's behavior by deriving a class SSLSocket from Socket and implementing the behavior of the higher SSL stack protocol on top of Socket. Now, let's say you get a new requirement to have the same protocol of communications, but over a USB line, or over telephony. You would need to cut and paste all that work to a new class that derives from a USB class, or a Telephony class. And now, if you find a bug, you have to fix it in all three places, which won't always happen, which means bugs will take longer and not always get fixed...
This is general to any inheritance hierarchy A->B->C->... When you want to use the behaviors you've extended in derived classes, like B, C, .. on objects not of the base class A, you've got to redesign or you are duplicating implementation. This leads to very monolithic designs that are very hard to change down the road (think Microsoft's MFC, or their .NET, or - well, they make this mistake a lot). Instead, you should almost always think of extension through composition whenever possible. Inheritance should be used when you are thinking "Open / Closed Principle". You should have abstract base classes and dynamic polymorphism runtime through inherited class, each will full implementations. Hierarchies shouldn't be deep - almost always two levels. Only use more than two when you have different dynamic categories that go to a variety of functions that need that distinction for type safety. In those cases, use abstract bases until the leaf classes, which have the implementation.
Maybe many people here will not like this answer, but it is time for some heresy to be told and yes ... be told also that "the king is naked!"
All the motivation against the derivation are weak. Derivation is not different than composition. It's just a way to "put things together".
Composition puts things together giving them names, inheritance does it without giving explicit names.
If you need a vector that has the same interface and implementation of std::vector plus something more, you can:
use composition and rewrite all the embedded object function prototypes implementing function that delegates them (and if they are 10000... yes: be prepared to rewrite all those 10000) or...
inherit it and add just what you need (and ... just rewrite constructors, until C++ lawyers will decide to let them be inheritable as well: I still remember 10 year ago zealot discussion about "why ctors cannot call each other" and why it is a "bad bad bad thing" ... until C++11 permitted it and suddenly all those zealots shut up!) and let the new destructor be non-virtual as it was in the original one.
Just like for every class that has some virtual method and some not, you know you cannot pretend to invoke the non-virtual method of derived by addressing the base, the same applies for delete. There is no reason just for delete to pretend any particular special care.
A programmer who knows that whatever is not virtual isn't callable addressing the base, also knows not to use delete on your base after allocating your derived.
All the "avoid this", "don't do that", always sound as "moralization" of something that is natively agnostic. All the features of a language exist to solve some problem. The fact a given way to solve the problem is good or bad depends on the context, not on the feature itself.
If what you're doing needs to serve many containers, inheritance is probably not the way (you have to redo for all). If it is for a specific case ... inheritance is a way to compose. Forget OOP purisms: C++ is not a "pure OOP" language, and containers are not OOP at all.
Publicly inheriting is a problem for all the reasons others have stated, namely that your container can be upcasted to the base class which does not have a virtual destructor or virtual assignment operator, which can lead to slicing problems.
Privately inheriting, on the other hand, is less of an issue. Consider the following example:
#include <vector>
#include <iostream>
// private inheritance, nobody else knows about the inheritance, so nobody is upcasting my
// container to a std::vector
template <class T> class MyVector : private std::vector<T>
{
private:
// in case I changed to boost or something later, I don't have to update everything below
typedef std::vector<T> base_vector;
public:
typedef typename base_vector::size_type size_type;
typedef typename base_vector::iterator iterator;
typedef typename base_vector::const_iterator const_iterator;
using base_vector::operator[];
using base_vector::begin;
using base_vector::clear;
using base_vector::end;
using base_vector::erase;
using base_vector::push_back;
using base_vector::reserve;
using base_vector::resize;
using base_vector::size;
// custom extension
void reverse()
{
std::reverse(this->begin(), this->end());
}
void print_to_console()
{
for (auto it = this->begin(); it != this->end(); ++it)
{
std::cout << *it << '\n';
}
}
};
int main(int argc, char** argv)
{
MyVector<int> intArray;
intArray.resize(10);
for (int i = 0; i < 10; ++i)
{
intArray[i] = i + 1;
}
intArray.print_to_console();
intArray.reverse();
intArray.print_to_console();
for (auto it = intArray.begin(); it != intArray.end();)
{
it = intArray.erase(it);
}
intArray.print_to_console();
return 0;
}
OUTPUT:
1
2
3
4
5
6
7
8
9
10
10
9
8
7
6
5
4
3
2
1
Clean and simple, and gives you the freedom to extend std containers without much effort.
And if you think about doing something silly, like this:
std::vector<int>* stdVector = &intArray;
You get this:
error C2243: 'type cast': conversion from 'MyVector<int> *' to 'std::vector<T,std::allocator<_Ty>> *' exists, but is inaccessible
You should refrain from deriving publicly from standard contianers. You may choose between private inheritance and composition and it seems to me that all the general guidelines indicate that composition is better here since you don't override any function. Don't derive publicly form STL containers - there really isn't any need of it.
By the way, if you want to add a bunch of algorithms to the container, consider adding them as freestanding functions taking an iterator range.
The problem is that you, or someone else, might accidentally pass your extended class to a function expecting a reference to the base class. That will effectively (and silently!) slice off the extensions and create some hard to find bugs.
Having to write some forwarding functions seems like a small price to pay in comparison.
Because you can never guarantee that you haven't used them in a polymorphic way. You're begging for problems. Taking the effort to write a few functions is no big deal, and, well, even wanting to do this is dubious at best. What happened to encapsulation?
Most common reason to want to inherit from the containers is because you want to add some member function to the class. Since stdlib itself is not modifiable, inheritance is thought to be the substitute. This does not work however. It's better to do a free function that takes a vector as parameter:
void f(std::vector<int> &v) { ... }
IMHO, I don't find any harm in inheriting STL containers if they are used as functionality extensions. (That's why I asked this question. :) )
The potential problem can occur when you try to pass the pointer/reference of your custom container to a standard container.
template<typename T>
struct MyVector : std::vector<T> {};
std::vector<int>* p = new MyVector<int>;
//....
delete p; // oops "Undefined Behavior"; as vector::~vector() is not 'virtual'
Such problems can be avoided consciously, provided good programming practice is followed.
If I want to take extreme care then I can go upto this:
#include<vector>
template<typename T>
struct MyVector : std::vector<T> {};
#define vector DONT_USE
Which will disallow using vector entirely.
I have about 15~20 member variables which needs to be accessed, I was wondering
if it would be good just to let them be public instead of giving every one of them
get/set functions.
The code would be something like
class A { // a singleton class
public:
static A* get();
B x, y, z;
// ... a lot of other object that should only have one copy
// and doesn't change often
private:
A();
virtual ~A();
static A* a;
};
I have also thought about putting the variables into an array, but I don't
know the best way to do a lookup table, would it be better to put them in an array?
EDIT:
Is there a better way than Singleton class to put them in a collection
The C++ world isn't quite as hung up on "everything must be hidden behind accessors/mutators/whatever-they-decide-to-call-them-todays" as some OO-supporting languages.
With that said, it's a bit hard to say what the best approach is, given your limited description.
If your class is simply a 'bag of data' for some other process, than using a struct instead of a class (the only difference is that all members default to public) can be appropriate.
If the class actually does something, however, you might find it more appropriate to group your get/set routines together by function/aspect or interface.
As I mentioned, it's a bit hard to tell without more information.
EDIT: Singleton classes are not smelly code in and of themselves, but you do need to be a bit careful with them. If a singleton is taking care of preference data or something similar, it only makes sense to make individual accessors for each data element.
If, on the other hand, you're storing generic input data in a singleton, it might be time to rethink the design.
You could place them in a POD structure and provide access to an object of that type :
struct VariablesHolder
{
int a;
float b;
char c[20];
};
class A
{
public:
A() : vh()
{
}
VariablesHolder& Access()
{
return vh;
}
const VariablesHolder& Get() const
{
return vh;
}
private:
VariablesHolder vh;
};
No that wouldn't be good. Image you want to change the way they are accessed in the future. For example remove one member variable and let the get/set functions compute its value.
It really depends on why you want to give access to them, how likely they are to change, how much code uses them, how problematic having to rewrite or recompile that code is, how fast access needs to be, whether you need/want virtual access, what's more convenient and intuitive in the using code etc.. Wanting to give access to so many things may be a sign of poor design, or it may be 100% appropriate. Using get/set functions has much more potential benefit for volatile (unstable / possibly subject to frequent tweaks) low-level code that could be used by a large number of client apps.
Given your edit, an array makes sense if your client is likely to want to access the values in a loop, or a numeric index is inherently meaningful. For example, if they're chronologically ordered data samples, an index sounds good. Summarily, arrays make it easier to provide algorithms to work with any or all of the indices - you have to consider whether that's useful to your clients; if not, try to avoid it as it may make it easier to mistakenly access the wrong values, particularly if say two people branch some code, add an extra value at the end, then try to merge their changes. Sometimes it makes sense to provide arrays and named access, or an enum with meaningful names for indices.
This is a horrible design choice, as it allows any component to modify any of these variables. Furthermore, since access to these variables is done directly, you have no way to impose any invariant on the values, and if suddenly you decide to multithread your program, you won't have a single set of functions that need to be mutex-protected, but rather you will have to go off and find every single use of every single data member and individually lock those usages. In general, one should:
Not use singletons or global variables; they introduce subtle, implicit dependencies between components that allow seemingly independent components to interfere with each other.
Make variables const wherever possible and provide setters only where absolutely required.
Never make variables public (unless you are creating a POD struct, and even then, it is best to create POD structs only as an internal implementation detail and not expose them in the API).
Also, you mentioned that you need to use an array. You can use vector<B> or vector<B*> to create a dynamically-sized array of objects of type B or type B*. Rather than using A::getA() to access your singleton instance; it would be better to have functions that need type A to take a parameter of type const A&. This will make the dependency explicit, and it will also limit which functions can modify the members of that class (pass A* or A& to functions that need to mutate it).
As a convention, if you want a data structure to hold several public fields (plain old data), I would suggest using a struct (and use in tandem with other classes -- builder, flyweight, memento, and other design patterns).
Classes generally mean that you're defining an encapsulated data type, so the OOP rule is to hide data members.
In terms of efficiency, modern compilers optimize away calls to accessors/mutators, so the impact on performance would be non-existent.
In terms of extensibility, methods are definitely a win because derived classes would be able to override these (if virtual). Another benefit is that logic to check/observe/notify data can be added if data is accessed via member functions.
Public members in a base class is generally a difficult to keep track of.
After storing objects of different types in the same container using common parent class I need to extract them back.
[Tests/test0.c++]:
int main()
{
element wrapper;
wrapper.name = "div";
wrapper.attributes["id"] = "wrapper";
cargo<string> text("Learn from yesterday, live for today, hope for tomorrow.");
wrapper.children.push_back(&text);
cout << "Name:\t" << wrapper.name << endl;
/* I have an explicit cast here,
* but it can't be used this way
* since children may have different types
*/
cout << "Cargo:\t" << ((cargo< string >*) wrapper.children[0])->value << endl;
return 0;
}
[Source/element.h]
struct element
{
std::string name;
std::map< std::string, std::string > attributes;
std::vector< node* > children;
};
[Source/node.h]
struct node
{ };
[Source/cargo.h]
template <typename Type>
struct cargo
: public node
{
Type value;
cargo(Type value)
: value(value)
{ }
};
I need to have some kind of type holder to be associated with real node type and use it in farther casting-extracting operations... Instead of that hard-coded one in my test.
UPDATE:
What I'm trying to do is a simple Document Object Model Data structure to use it as symbol table entry for my xml-like language parser. I don't want to use any existing XML library as they are very large. I think the idea of DOM is simple, so I can easily adopt it for some more complex operations, for example, by allowing generic types for the nodes in DOM tree using cargo<Type>. I recognize that the design I adopted may not be the most adequate! So I'm open to suggestions!
I would be thankful for any help!
This question is probably more about the design than implementation.
Although Boost.Variant and Boost.Any will work, they will be only a workaround. The real problem may be that variable part of responsibility of classes, derived from node class, is not encapsulated.
You could try to use composition instead. One host class used for common interface and appropriate amount of components/delegates/whatever (those are to be born from a solution design :) ).
Or... a totally different solution may fit you. You may want to venture to meta programing word and ditch the common interface. Instead entities like tuples (type lists) may be of help.
Best Regards,
Marcin
if you are simply streaming, you could implement the stream operators in the base class and then delegate to a method in the derived class, else look at the visitor pattern. Without having a real grasp of what kind of operations you are likely to be doing on cargo, it's difficult to make further suggestions...
If you don't plan on treating the container members polymorphically on retrieval, Boost.Variant might be useful to wrap the container members in a deterministic way.
The variant class template is a safe,
generic, stack-based discriminated
union container, offering a simple
solution for manipulating an object
from a heterogeneous set of types in a
uniform manner. Whereas standard
containers such as std::vector may be
thought of as "multi-value, single
type," variant is "multi-type, single
value."
There's some example code in this prior question.
You won't get along something like this without a cast.
But most importantly, this often means that you're going the wrong way. As long as you decided cargo would inherit publicly from node, you provided a very strong relationship between the two classes, and 'being a node' has a much stronger meaning than :
I can be inserted in a container
along with other node derived types
We need to know what is a node and what can be done with it to help you further. However if you really need to stick with your initial solution, boost.variant could help you.
You should design so the code doesn't care about the base class type. Provide an interface that is the same for all. Or add the pure virtual methods you need to the base class and implement in derived class.
Assuming that is some how not possible, have you tried dynamic_cast? It returns null if the cast fails, rather than throwing as your static_cast above will do.
Hope this helps,
Beezler