Let me explain my problem again. I have three classes which are admin, staff and HR which derived from human.
I have abstract factory pattern that simulate run time vtable lookup like this class hierarchy.
Quote:
class userCreator (standAlone)
Admin Factory HR Factory Staff Factory : class object Factory
The userCreator has a map that forward the read creation to appropriate object factory derive class.
Therefore, i also use this idea again to create my command pattern.
Quote:
class commander (stand alone) Forward call to derived class of genericCommander
AdminCommander HRCommander StaffComamnder : class GenericCommander
Now my problem is to forward call based on the user creation which wraps in smart pointer to derived class of genericCommander.
I don't know whether the solution a base class command and a derived class template suit to this situation or not because since template require compile time template parameter.
Back to your reply. I really thanks for your reply. Although, i didn't understand that.
Quote:
You say the error is runtime, but how does this compile?
theCommander.insert(commandCont::value_type(AdministratorPtr, AdministratorCommandPtr) );
theCommander.insert(commandCont::value_type(HumanResourcePtr, HRCommandPtr) );
theCommander.insert(commandCont::value_type(StaffPtr, StaffCommandPtr) );
theCommander expects a HumanPtr, right? (I'm not 100% certain I follow the snippet entirely).
typedef std::map<HumanPtr, GenericCommandPtr> commandCont;
commandCont theCommander;
I also have no idea why this compile because i don't know there is no polymorphic in smart pointer.
Quote:
However, while:
Human *p = new Staff;
is valid, because a Staff is a Human
shared_ptr<Staff> sps( new Staff );
shared_ptr<Human> sph;
sph = sps; // compiler error.
The problem here is that a shared_ptr<Staff> is not related to a shared_ptr<Human> even though a Staff is a Human.
This is because sph and sps are types - once the template is instantiated it becomes what I'll call a "unified" type.
In order to make a shared_ptr<Human> relate to a shared_ptr<Staff>, you'd have to expect the compiler to decompose the type into the constituent components that went into creating that type, and it can't.
That would be a runtime notion, not a compile time notion.
So I'm not sure I understand how the code compiles as is (I think it's through value_type that it could be happening).
I understand this. Thanks.
I found some weird issue where below code compiles fine.
Code:
shared_ptr<Staff> sps( new Staff() );
shared_ptr<Human> sph;
sph = sps; // compiler error.
I using MS VS C++ 2008.
Quote:
If theCommander requires shared_ptr<Human> (which makes sense), then everything going into or out of it must be shared_ptr<Human>.....though certainly it makes sense for....
shared_ptr<Human> sph( new Staff );
...and the other derivatives..
The shared_ptr<Human> is holding any of the derivative types - no problem there.
However, a container - any container, like list, must work on a single type...
list<shared_ptr<Human> > hlist;
This container can't take shared_ptr<Staff>.
It must take shared_ptr<Human>, even if that shared pointer contains a Staff.
I also understand this.
Quote:
Is that illuminating or am I the one missing something?
I think I sense the next question though.
How can function pointers be generic through shared_ptr<Human>? How can Staff functions be stored in shared_ptr<Human>?
...short answer, they can't.
No, i don't want staff function to store in shared_ptr and it shouldn't.
Quote:
What you'll need is an even more generic non-template base.
shared_ptr<memfuncptr> perhaps.
It doesn't know what object it's going to call.
shared_ptr<memfuncptr> mfp( new memfunc<Staff> );
What I'm suggesting here is two classes, memfuncptr which is the base, and memfunc<T> which is derived from memfuncptr.
The command container has no idea what type it's going to command. It could be any, non-related object.
It's only going to "understand" that it must, for example....
memfuncptr->CallFunction();
CallFunction would be a virtual function (probably void CallFunction()=0).
The shared_ptr<memfuncptr> has no problem with that. The "real" object there has a virtual function in memfunc<T> which
understands the object it's going to call (not the commander), and it might know the object.
I been suggested to use this common command pattern and i not understand this. I know that there are one class template derived from normal class.
Code:
class MenuEntryBase
{
public:
virtual ~MenuEntryBase() {}
virtual const string& text() = 0;
virtual void execute() = 0;
};
// Callback
template<class T>
class MenuEntry : public MenuEntryBase
{
string text_;
T& object_;
void (T::*function_)();
public:
MenuEntry(const string& txt, T& obj, void(T::*func)())
: text_(txt), object_(obj), function_(func) {}
const string& text() { return text_; }
void execute() { (object_.*function_)(); }
};
// Selection of Menu and display
class Menu
{
vector<MenuEntryBase*> entries;
public:
virtual ~Menu()
{
for (size_t i=0; i<entries.size(); ++i)
delete entries[i];
}
template<class T>
void addEntry(const string& txt, T& obj, void(T::*func)())
{
entries.push_back( new MenuEntry<T>(txt, obj, func) );
}
void display()
{
for (size_t i=0; i<entries.size(); ++i)
cout << i << ") " << entries[i]->text() << endl;
}
void select()
{
cout << endl << "Selection: ";
unsigned selection = 0;
cin >> selection;
if (selection < entries.size())
entries[selection]->execute();
cin.sync();
}
};
Code:
Staff *sp = new Staff;
commandPtr<Staff> cmd( sp );
shared_ptr<Human> hp( sp );
typedef std::map<HumanPtr, GenericCommandPtr> commandCont;
GenericCommandPtr is a shared_ptr base class for shared_ptr<AdministratorCommander>.
Quote:
There may be times you want the commander to share ownership of the instance to be called....
shared_ptr<Human> sph( new Staff );
sph owns the staff, and you want the commander to access it, but your call is going to be made on staff...
Staff::*fptr = &Staff::func;
Your only ownership is of Human, the base, and it doesn't know func (and shouldn't).
You "could" rely on casting....
commandPtr< Human, Staff > c( sph );
Unfortunate, but workable. You have to know sph is really a staff, and when the call comes, the shared_ptr you'll have is a shared_ptr<Human>.
You'd have to try something like:
Staff *sp = dynamic_cast<Staff>(sph.get()); // might be static_cast if the compiler is ok with that.
The two parameter commander might have the knowledge to cast from Human to Staff.
On the other hand, it might be better to wrap this in a different way.
Staff *sp = new Staff;
commandPtr<Staff> cmd( sp );
shared_ptr<Human> hp( sp );
Not understand this.
Quote:
...all pseudo code and over simplified...
The point is, you'd provide a very native command object that know's it refers to a Staff, not a human, and refers to it by pointer, not smart pointer, and does NOT act as though the pointer is an owner in any way. It now has a Staff * on which to do it's work.
You have to know hp is in a container who's scope will outlast the commandPtr, such that there is no way commandPtr could attempt the call on an object that was deleted already.
There are many variations on this theme, all related to the fact that shared_ptr<Staff> is a fundamentally different and incompatible type to shared_ptr<Human>, regardless of the fact that Staff is derived from Human.
Do not be tempted to solve this with something resolves to:
Staff *sp = new Staff;
shared_ptr<Human> hp( sp );
shared_ptr<Staff> sf( sp );
This will eventually result in double deletion, which should crash.
Understand.
Quote:
What you could do, if you need shared containment, is
commandPtr<Staff, Human>
where the shared_ptr<Human> performs containment on the common base, but a Staff * is used to make the Staff member call.
You would not use the shared_ptr<Human> for anything - it only holds the object.
Do not be tempted to pass the Staff * to the commandPtr, you'll end up with
shared_ptr<Human> hp( sp );
shared_ptr<Human> hp( sp );
Because, obviously, you could have a shared_ptr<Human> in an external container.
also a double deletion.
You should probably create a factory that casts, or creates shared_ptr<Human> on the Staff * for all purposes....
shared_ptr<commandPtr> cp;
shared_ptr<Human> hp = CreateObjects<Staff>(cp);
Which returns a shared_ptr<Human> which you can supply to external containers, and a correctly formed commandPtr for use in the command structure, all coordinated to control containment and casting issues at the time of creation, so everything is correctly synchronized.
Not understand this.
Thanks for your reply.