I'm trying to make an efficient "entity system" in C++, I've read a lot of blog/articles/documentation on the Internet to get lot of information but I've got some questions again.
I've find two interesting subjects:
Data-driven system
Entity component system
For me, the two systems look very similar.
So, I've found this example by Adam Smith: https://stackoverflow.com/a/2021868
I need to have a flexible system like this:
// Abstract class
class Component
{
// data here
}
// exemple
class Car : public Component
{
// Data here
}
// Entity with components
class Entity
{
std::vector<Component*> components;
}
So, if my entity have the followings components: Car, Transform, Sprite,
did my components array will had linear data like data-driven system?
Now, I have Systems:
class System
{
virtual void init();
virtual void clear();
virtual void update();
std::unordered_map< const char*, Entity*> entities;
}
class RendererSystem : public System
{
// Methods's definition (init, clear, …).
void update()
{
for( entity, … )
{
Sprite* s = entity->getComponent('sprite');
...
}
}
}
I've read that virtual functions are bad, it's bad in that case?
Get component need a static_cast, that's bad?
In data-driven system, I saw pointer everywhere, si where is the "original" variables, I need to put new everywhere or I will have a class with an array of same data?
Did I make this right?
All this points look "blur" in my mind.
Virtual functions do have some overhead but nothing that you should care about unless you are doing millions of calls per second so just ignore that fact.
A static cast is not bad by itself but it breaks static type checking where it is used so if you can move the behavior inside the object on which you cast so that you just call the appropriate method without having to know the specific runtime instance of an object then it's better
It's not clear what you are asking, even if you have vectors of element in a data-driven approach, each element in the collections needs to be allocated with a new (if it's a pointer). Then once you allocated it you won't need to do it again as soon as you will pass the reference to the item around
Related
How does the compiler treat a complete empty function to behave at runtime?
class Base
{
public:
virtual void execute(){ /* always empty */ }
};
example usage:
int main()
{
Base b;
b.execute();
return 0;
}
Am creating an entity system which should be able to have sub-classes which are only holding data. Those are called Properties. Some need to have a manipulation function to conclude the data. These classes are called Component.
The purpose is to be able to add functionality to a class at run-time and even later with additional shared libraries.
Due to the flexibility needed, and the wish to keep it as simple as possible, I came up with a shared Base class for the Properties and Component classes. See the code-block below.
However, the class Base contains the function execute() and is invoked in the final class Container for all the properties and components assigned to that class.
Maybe it is better to split the Property and Component entirely into two different identities, however they will rely on each other heavily, e.g. A property could be a transform (position, scale, quaternion, matrix) while a component can be an animation of that quaternion in the transform.
#include <vector>
class Base
{
public:
virtual void execute(){ /* always empty */ }
};
class Property // as manny will be
: public Base
{
public:
/* specifics */
};
class Component // as manny will be
: public Base
{
public:
/* specifics */
virtual void execute(){ /* do whatever */ }
};
class Container
{
public:
std::vector<Base*> list;
virtual void execute()
{
std::vector<Base>::iterator iterator = list.begin(), end = list.end();
while( iterator != end )
( *iterator )->execute();
}
}
Not knowing what the compiler actually does besides generating binaries, I don't think it would be an equivalent of a debug session going line by line.
How does the compiler treat such an empty function, would it be better to move the function execute(); to class Component as first declaration. Then add enum{ Property, Component }; to class Property so a if-statement can determine to call the execution function.
Virtual functions are very cheap to call, but depending on the number of different sub-classes a switch could be faster (the reason is that a switch will not create another execution context) but of course a lot less flexible. This is especially true if to implement the body of execute method most of them will share part of the processing and data access (like for example for different instructions of a virtual machine) because part of that could be cached out of the loop.
Keeping properties in the same container and leaving them with an empty execute method doesn't seem reasonable to me, but this could be just lack of context of the problem being solved.
The general rule is however to stop assuming and start measuring, with real data and real usage pattern. Performance forecasting is today very complex (almost impossibly complex) because CPUs are little monsters of complexity on their own and there are many of them. You need to test to find where the time is spent... guessing doesn't work that well.
My first approach would be using virtual functions and keeping things as simple as possible. Inlining those functions in a loop would only come later if I measure that the dispatch overhead is the problem and that there are no bigger wins to be searched in other areas.
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.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Ok so I have tried implementing simple mono alphabetic substitution ciphers like Caesars , digraph like playfair , polyalphabetic ones like autokey, vigenre and a few others in c++ {without using classes}. Now i would like to bring together all these ciphers and a few others and package it into a single project.I have started coding a few lines, but i'm not sure how i must design it. Here's how my classes look.
my front end
//main.cpp contains few switch cases to chose the right cipher for encryption.
//cipher.cpp implements class cipher.In a crude format the class looks like
class cipher
{
protected:
string plaintxt,ciphertxt;
public:
virtual bool encrypt()=0;
virtual bool decrypt()=0;
virtual bool tabulate()=0;
}
this class is interfaced by cipher.h
//mono_alphabetic.cpp implemants the class mono_alpha
class mono_alpha : public cipher
{
protected:
map<string,string> Etable,Dtable;
public:
bool Encrypt();
bool Decrypt();
}
Now i'm using a simple example of atbash cipher here.For those of you who don't know what an atbash cipher is, it is a mode of encryption in which each character in a given string is encrypted with its equivalent character as per position in the reverse alphabetic order. For eg. A ->Z Z->A B->Y M->N so on.
class atbash : public mono_alpha
{
public:
bool tabulate(); // makes a hash map were A is mapped to Z M to N e.t.c
atbash(string&); // accepts a string and copies it to string plaintxt.
}
This is a very crude example. Only the class design is presented here.Here are a few doubts of mine.
implemantation : I would accepts a string from the user and then pass it to the constructor of class atbash, where it is copied to the string data member plaintxt inherited from the base class cipher. Then i would invoke the function tabulate from the constructor.Now i have two choices either tabulate() generates a hash map of encryption table and store it in Etable, or it could also generate the decryption table.In the case of an atbash cipher these are one but the same. But what about the case of a general mono alphabetic substitution cipher ? how would i force the tabulate functio to create either one.
my idea was to pass a character argument to the constructor to the constructor which describes if the given string is to be encrypted or decrypted and accordingly saves it in either one among plaintxt or ciphertxt.Further the constructor passes this character argument to tabulate function which tabulates the encryption or decryption table accordingly.Is this good ?
any suggestion on how to improve this ?
interface : my way of implementing an interface to all these ciphers from main.cpp was to use swith case like.
switch(chosen_value)
{
case 1: cout<<"atbash encryption";
cipher*ptr = new atbash ("a string");
// ptr->tabulate(); if it isn't being called directly from the constructor.(here it is)
case 2:
cout<< "caeser's cipher";
.....................
.
.....
}
Are there any better ways to implement this without using switch case.
also as you can see i have used a base class pointer to an object of the derived class for doing this.I know it isn't necessary here and the I can simply proceed by declaring an object. Is there any real importance to referencing objects through a base class pointer ?
I have heard that these base class pointers can be a real life savior sometimes ! If so please direct me on scenarios where this simplifies coding . Is declaring pure virtual functions in the base class not of any use in this particular case.Is it just bloating the code here ?
should i go on with separating the class implementations into separate files like i have done here or should i just cramp up all these code in a single main.cpp which would make inheritance a lot easier as you don't have to use header files.
Please guide me on this.I have zero professional experience in coding and would love to here your opinions.
Some ideas, in no particular order
Have different classes for encryption and for decryption. That will solve your doubt on what to use. So the cipher base class becomes a base class for a transformation of a string into other. (not an expert on patterns, but I believe this is the Command Pattern)
The nice thing about having an object to represent the algorithm is that it can have state. You might want to add a reset() method to be able to reuse the object on a new execution if the creation of the object is expensive.
You can make the base class a function object with an abstract operator(). This operator() gets implemented in each specific encryption and descryption classes. Using this allows you to handle this classes as functions (the downside is that it is perhaps less clear what you're doing).
It is correct to handle everything through pointers to the base class (or references or smart pointers)
In order to create the right type of operation, have a Factory class (this is again a pattern). This can be a class with a creator method where you indicate the algorithm and the encryption/decryption direction. The Factory returns a pointer to the base class, pointing the appropriate implementation.
The implementation can be a vector or a map or an array of some specific factory objects (whose job is to instantiate an algorithm object of the different types)... Alternative you can have a static method on each derived class and store a pointer to method in the structure.
The structure (vector/map/array/whatever) is used for fast selection of the right algorithm. If the number of algorighms is small, the use of a switch statement is probably fine. The structure is contained in the Factory class and initialize on its constructor.
You must mind the lifecycle of the objects created. Objects are created by the Factory, but who should destroy them?
Consider what you're going to use to represent the encrypted/decrypted messages and wether they become non-printable or they can become too large.
There are many design decisions here, many trade offs that depends on different things.
Hope the above lines give you some ideas to start.
Edit: adding a more concrete example
We will start with an Operation class. This assumes that we can have both encrypters and decrypters can be called with the same API
class Operation {
public:
virtual ~Operation() { }
virtual std::string operator()(const std::string &input)=0;
virtual void reset() { }
};
Notes on this:
Assumes that the API is string input gives a string output. This is the operator() pure virtual method.
Added a virtual destructor. We're going to be dealing mostly with references to Operation. However implementations of the algorithm my need to destroy their own things, so the destructor must be virtual so that when deleting an Operation pointer it will also invoke the destructor of the derived class.
Added a reset() method. This has a default implementation that does nothing. Potentially derived classes might store state, this method is intended to return the operation to its initial step so that you don't have to scrap it and create another.
Now some of the derived classes:
class MyEncoder: public Operation {
public:
static Operation *create() {
return new MyEncoder();
}
std::string operator()(const std::string &input) {
// Do things.
return std::string();
}
};
class MyDecoder: public Operation { ... };
class OtherEncoder: public Operation { ... };
class OtherDecoder: public Operation { ... };
I'm only showing in full MyEncoder We see a static method create that we will talk about later.
The implementation of the algorithm happens on the implementation of the operator()
You could:
Keep state in attributes of MyEncoder
Initialize stuff on constructor
... and perhaps destroy things in a destructor.
Potentially include an implementation of the reset() method to reuse the object in another invocation.
Now for the Factory:
class OperationFactory {
public:
enum OperationDirection {
OD_DECODER=0,
OD_ENCODER
};
enum OperationType {
OT_MY=0,
OT_OTHER
};
....
};
Just declared the class and a couple of enumerations to help us distinguish between encoders and decoders and the two algorithm I'm going to use.
We need some place to store things, so the Factory class ends with:
class OperationFactory {
public:
...
private:
typedef Operation *(*Creator)();
typedef std::map<OperationType,Creator> OperationMap;
OperationMap mEncoders;
OperationMap mDecoders;
};
Here:
The first typedef gives a name to a function pointer. This is a function that takes no arguments and returns a pointer to an Operation. A static method is the same as a function (at least regarding function pointers)... so this typedef allows us to give a name to the mysterious create() static method we had above.
The second typedef is just shortcut for the lengthy std::map definition. This is a map from OperatonType to Creator function.
We define two of those maps, one for Encoder, one for Decoders. You could devise a different way.
With that we can provide some methods for the user to obtain what it wants:
class OperationFactory {
public:
...
Operation *getOperation(OperationDirection _direction,OperationType _type) const {
switch(_direction) {
case OD_DECODER:
return getDecoder(_type);
case OD_ENCODER:
return getEncoder(_type);
default:
// Or perhaps throw an exception
return 0;
}
}
Operation *getEncoder(OperationType _type) const {
OperationMap::const_iterator it=mEncoders.find(_type);
if(it!=mEncoders.end()) {
Creator creator=it->second;
return (*creator)();
} else {
// Or perhaps throw an exception
return 0;
}
}
Operation *getDecoder(OperationType _type) const {
.... // similar but over the mDecoders
}
....
};
So, we look up the OperationType in the map and get a pointer to a function (Creator) type, we can call this function (*creator)() to obtain the instance of the Operation that we requested.
Some words on (*creator)():
creator is of type Creator... so it is a pointer to a function.
(*creator) is the function (the same as if p is an int *, *p is of type int)...
(*creator)() is the invocation of a function.
To complete this we need to really have something in the map... so we add that on the constructor:
class OperationFactory {
public:
....
OperationFactory() {
mEncoders[OT_MY]=&MyEncoder::create;
mEncoders[OT_MY]=&MyDecoder::create;
mEncoders[OT_OTHER]=&OtherEncoder::create;
mEncoders[OT_OTHER]=&OtherDecoder::create;
}
....
};
We insert for each algorithm the pointer to their create static methods.
Finally how do we use it?
int main(int argc,char **argv) {
OperationFactory f;
Operation *o=f.getOperation(OperationFactory::OD_DECODER,OperationFactory::OT_MY);
std::string toTransform="Hello world";
std::string transformed=(*o)(toTransform);
delete o; // don't forget to delete it.
}
Here we have an instance of the OperationFactory f from where we can request the creation of our desired operation with the getOperation() methods.
The object that we got can be used to execute the algorithm. Note that (*o)(toTransform) is formaly similar to our invocation of creator above, but there are differences:
o is a pointer to an object of type Operation (actually is really a pointer MyEncoder)
(*o) is an object of typeOperation(well, really of typeMyEnconder`)
(*o)(toTransform) is the invocation of the operator() method of the MyEncoder type.
We could have used this technique on the Creator: using an object-function instead of a pointer to function... but it would have been more code.
Note that the factory allocates memory... and this memory must be disposed when no longer needed. Ways of not doing this are to use unique_ptr or shared_ptr...
Note that getOperation() could return a null pointer when it cannot find the algorithm requested... so the calling code should check for that possibility.
Alternatively the implementation of getOperation() could have chosen to throw an exception when the algorithm is not found... again the calling code should then have had a try/catch.
Now, how to add a new algorithm:
Derive and implement your encoder and decoder classes from Operation
Expand the enum OperationType
register the creators in the OperationFactory constructor.
... use it.
//////////////////////////////////////////////////////////////////////////////////////////
// Note: Automatically generate getter and setter
template<typename T>
class Wrap {
public:
...
const T& operator()() const
{
return m_element;
}
void operator()(const T& element)
{
m_element = element;
}
...
private:
T m_element;
};
// Pro: The container may have more than 20 different member variables.
// Each goes with a simple getter and setter for now. Due to the Wrap
// class, we don't have to add getter and setter for any new variable
// Con: Since this is a public API interface, if the user directly adopt the
// Wrap class, it is difficult for any future improvement. Based on this design,
// we cannot make Wrap private embeded class of Container since the user needs to
// access those public member variables of Container
class Container
{
public:
Wrap<int> Age;
Wrap<double> Balance;
...
};
//////////////////////////////////////////////////////////////////////////////////////////
// Con: For each different member variable, we have to add getter and setter methods
// which will be a problem considering if you have 20 member variables.
// Pro:
// By using PIMPL pattern, we can make the interface more robust for future improvement
// without breaking our client's code.
class PimplClass
{
public:
int Age() const;
PimplClass& Age(int _age);
double Balance() const;
PimplClass& Balance(double _balance);
private:
Pimpl* m_data; // hide internal data structure from the public API interface
};
//////////////////////////////////////////////////////////////////////////////////////////
Question> Is there a better design that I can combine both auto getter+setter generation and PIMPL design pattern
into this public API interface?
Thank you
// ****** Updated ************
After reading all those articles, I am convinced that getter and setter are evil. Now the question comes to how to avoid them all together.
For example,
class Bond
{
...
private:
long m_lPrice;
std::string m_strBondName;
int m_iVolume;
}
Give the above class Bond which includes three member variables, without using getter and setter, how does client get the price, name, or volume of an bond object?
This is the another example of getter/setter in Qt4.
Here's the improved QProgressBar API:
class QProgressBar : public QWidget
{
...
public:
void setMinimum(int minimum);
int minimum() const;
void setMaximum(int maximum);
int maximum() const;
void setRange(int minimum, int maximum);
int value() const;
virtual QString text() const;
void setTextVisible(bool visible);
bool isTextVisible() const;
Qt::Alignment alignment() const;
void setAlignment(Qt::Alignment alignment);
public slots:
void reset();
void setValue(int value);
signals:
void valueChanged(int value);
...
};
Thank you
Getters and setters are there so that you can "grab" into an object's guts and fiddle with its innards. That should make your alarm bells ring very loudly. For a well-designed class, you do not have to dig through its guts, since it lets you do everything you need to do through its interface without leaking any of its implementation details through the abstraction.
Design a class from the point of view of a user of the class ("if I have a qrxl object, I would need to make it wrgl() like this, and I also need to pass it a lrxl object occasionally, which it then uses to do frgl()"), rather than from the point of view of the implementer who needs to somehow organize his data and algorithms into useful (for him!) chunks. ("Let's just put this Johnny over here into that class, because that's where it is close to where I need it for implementing the xrxl() algorithm.")
I think in this regard Java has done a huge disservice to humanity in that it requires you to put everything into some class, even if this is against how you actually visualize your design in your head, and even if you are not (yet) thinking object-oriented. This seems to have made a design style en vogue where programmers just stuff everything into some class somewhere because "that's the way it's done."
In lots of Java code I've seen the underlying programming style is actually Structured Programming (basically "collect your data in useful chunks, and pass those to your algorithms", as done in C or Pascal), rather than Object-oriented Programming. Just because you replace struct/record by class and make the data members in this chunk only accessible through getters and setters, this doesn't mean you are doing object-oriented programming.1 This is what the author of that wonderful short paper calls pseudo classes
From what little I know about Qt, its design is also a pretty good example for a pretty bad example, with everything allocated on the heap, handed around in naked pointers, and employing the quasi-class school of design.
Give the above class Bond which includes three member variables, without using getter and setter, how does client get the price, name, or volume of an bond object?
This is the wrong question. The right question is why would a user need to get at those values? If you need to get at them manually, then Bond isn't high enough an abstraction for OO design, it's a mere C-style struct where you throw together all the data you need in one place. Ask yourself:
What would a user of a Bond want to do with such an object? How can I make the class support those operations without users having to grab into it and fiddle with its guts? How can I make the classes that interact with Bond do this? Can I pass them Bond objects, rather than price, name, or volume of an bond object?
Yes, sometimes you have to have just a bond's price in order to display it, and if that's the case, then Bond will need to support a getter function for the price, and that's Ok then. But you could still pass a Bond object to your BondPriceTable's displayBonds() function, and let that decide whether it wants to just grab the name and the price and throw that at the screen or display more values. There is no need to extract name and price manually and pass those to a display() function.
1 That's especially appalling because Java aficionados so often look down at C++ for not being "purely OO".
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.