|
-
July 31st, 2009, 03:17 AM
#1
Smart Pointer Map Lookup
Hello to all, i have a smart pointer declare like this.
Code:
shared_ptr<Human> HumanPtr;
The class Human has several derived classes such as Admin, Staff and HR.
I have another class called commander has shared_ptr<Human> HumanPtr as member.
The class commander has a map lookup table the declare like
Code:
ypedef std::map<HumanPtr, GenericCommandPtr> commandCont;
I wan to lookup the appropriate GenericCommandPtr based on the member HumanPtr and forward to the GenericCommandPtr derive class.
My code:
Code:
Commander commandPtr(thePtr);
commandPtr.ForwardCommand();
class Commander
{
private:
typedef boost::shared_ptr<GenericCommander> GenericCommandPtr;
typedef boost::shared_ptr<Human> HumanPtr;
typedef std::map<HumanPtr, GenericCommandPtr> commandCont;
// Lookup table like vtable
commandCont theCommander;
HumanPtr theRealUserPtr;
public:
Commander();
explicit Commander(const HumanPtr&);
~Commander();
void RegisterCommanderInstance();
void ForwardCommand();
};
Commander::Commander()
: theCommander(commandCont()),
theRealUserPtr(HumanPtr())
{
}
// =========================================
Commander::Commander(const HumanPtr& userInstancePtr)
: theCommander(commandCont()),
theRealUserPtr(userInstancePtr)
{
}
// =========================================
Commander::~Commander()
{
}
// =========================================
void Commander::RegisterCommanderInstance()
{
static shared_ptr<Administrator> AdministratorPtr(new Administrator());
static shared_ptr<HumanResource> HumanResourcePtr(new HumanResource());
static shared_ptr<Staff> StaffPtr(new Staff());
static GenericCommandPtr AdministratorCommandPtr(new AdministratorCommander() );
static GenericCommandPtr HRCommandPtr(new HRCommander() );
static GenericCommandPtr StaffCommandPtr(new StaffCommander() );
theCommander.insert(commandCont::value_type(AdministratorPtr, AdministratorCommandPtr) );
theCommander.insert(commandCont::value_type(HumanResourcePtr, HRCommandPtr) );
theCommander.insert(commandCont::value_type(StaffPtr, StaffCommandPtr) );
}
// =========================================
void Commander::ForwardCommand()
{
theCommander.find(theRealUserPtr)->second;
}
Code:
void Commander::ForwardCommand()
{
theCommander.find(theRealUserPtr)->second;
}
This code cause run time error map iterator not deference able.
The purpose of this program is to look up the appropriate GenericCommandPtr class.
Please help.
It really urgent.
Thanks.
Last edited by Peter_APIIT; July 31st, 2009 at 03:23 AM.
Thanks for your help.
-
July 31st, 2009, 09:02 AM
#2
Re: Smart Pointer Map Lookup
You say the error is runtime, but how does this compile?
Code:
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).
For example, StaffPtr is a shared_ptr<Staff>.
Staff is derived from Human.
Fine.
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).
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.
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.
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.
The issue comes in where you might contain Staff as...
shared_ptr<Human> hp;
This might be from a container of Humans, non related to the commander, but is used to populate the commander. This could get a little sticky because you can't....
shared_ptr<Staff> p = hp;
So, you need a weaker hold, and it takes some thought.
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 );
...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.
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.
Last edited by JVene; July 31st, 2009 at 09:35 AM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
August 1st, 2009, 03:01 AM
#3
Re: Smart Pointer Map Lookup
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.
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.
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.
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.
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.
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.
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.
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>.
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.
...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.
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.
Thanks for your help.
-
August 1st, 2009, 09:59 AM
#4
Re: Smart Pointer Map Lookup
I'm still reading through your recent post, a little rushed just now, I'll come back with more.
I thought, however, I'd reply to this point:
Code:
shared_ptr<Staff> sps( new Staff() );
shared_ptr<Human> sph;
sph = sps; // compiler error.
Ok, my bad here.
I've used smart pointers since before they were smart - before templates, they were a lot dumber.
For many years the smart pointers I've used come from various libraries, and about 99.9% of them can't compile this code.
Alexandrescu's book "Modern C++" described in his "loki" framework a smart pointer based on policies, typelists, and a range of issues that do permit this type of code to compile.
I avoided shared_ptr for some time, in favor of a set of smart pointers I could use when boost wasn't available. I switched TO shared_ptr when it was accepted into tr1.
I did NOT research sufficiently to realize they gave shared_ptr the ability to do this, so indeed - it is valid.
You can push a shared_ptr<Staff> into a container built for shared_ptr<Human>...
list<shared_ptr<Human>> list;
shared_ptr<Staff> sp( new Staff );
list.push_back( sp );
This works, and it's a pleasant surprise. It takes quite a bit of generic programming under the hood to make this work, and I didn't realize (I should have) that this shared_ptr is so featured.
It's great...
It does mean, however, that the pointer in list is going to be a shared_ptr<Human>, not a shared_ptr<Staff>, but that does mean the pointers are behaving a little more like native pointers would.
Skimming through the latter material in your post it seems you're all set with this, so it's not a mystery that the compiler allows it (I'm on VS2008 also, and I have two skeletal projects of your name which I'm using to test some of the code in our conversation - it does just fine).
I'll post back when I have more time on the rest of it.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
August 1st, 2009, 10:32 AM
#5
Re: Smart Pointer Map Lookup
I look forward any suggestion.
Thanks.
Thanks for your help.
-
August 1st, 2009, 01:59 PM
#6
Re: Smart Pointer Map Lookup
 Originally Posted by JVene
This works, and it's a pleasant surprise. It takes quite a bit of generic programming under the hood to make this work, and I didn't realize (I should have) that this shared_ptr is so featured.
Are you sure it is as complicated as you say? I had the impression that this was due to a shared_ptr constructor that allows an implicit conversion from a shared_ptr of a derived type to a shared_ptr of a base type (or of types that are otherwise convertible). This is akin to what was provided for auto_ptr.
-
August 1st, 2009, 05:34 PM
#7
Re: Smart Pointer Map Lookup
 Originally Posted by Peter_APIIT
This code cause run time error map iterator not deference able.
If it's a runtime error you're probably manipulating the map (restructuring it by making insertions or deletions) while you're iterating it. That's a big no-no.
When it comes to the behaviour of smart pointers (boost::shared_ptr) related to "bald" pointers - they're very close to totally identical in my view. I often amaze at this. Any difference is caught at compile time in my experience.
Last edited by nuzzle; August 1st, 2009 at 05:36 PM.
-
August 1st, 2009, 07:04 PM
#8
Re: Smart Pointer Map Lookup
laserlight, it's true that it's not especially deep, but it did take some care and planning.
For example, the assignment operator is a template function, adapting to the input type.
There is constructor overload that's also a template function, not a common idiom.
Certainly it's not black magic. I observe a wide range of code that comes from the early 90's, when the STL didn't yet exist, and 'custom' smart pointers were fairly common. At that time it would have been too much for the little 32Mbyte and 64Mbyte Pentium 90 based workstations on Borland C++ 4.5 or Visual Studio (I forget which version, maybe 4.1 or 4.2) to chug through something like shared_ptr without choking on VM.
Also, in order to cast from base to derived one must resort to a template function, like dynamic_pointer_cast, which is capable of converting from base to child smart pointer types. This function, too, isn't dark knowledge, but the whole thing does take finesse quite beyond the simpler smart pointers like auto_ptr, partly because of the underlying node which stores the reference counts.
A naive smart pointer with reference counting is very simple to build, and by itself can be quite useful, and were the norm in older work because their simplicity was actually possible in the older hardware.
Old habits die hard, and I became so accustomed to the older smart pointers that can't allow any form of such support that I never bothered to check if shared_ptr supported it.
Last edited by JVene; August 1st, 2009 at 07:07 PM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
August 1st, 2009, 11:02 PM
#9
Re: Smart Pointer Map Lookup
OK. Laserlight and JVene. One learn standard STL and another one is learn C++ before STL is formed.
I understand that smart pointer provided a template Copy constructor or assignment operator.
Does anyone have a suggestion to my problem ? It is urgent. I need to pass up my assignment.
I did some research and nothing concrete found.
Thanks.
Last edited by Peter_APIIT; August 1st, 2009 at 11:05 PM.
Thanks for your help.
-
August 2nd, 2009, 08:02 PM
#10
Re: Smart Pointer Map Lookup
Yes, sorry about the thread drift.
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.
I'm not entirely sure I do understand the question.
I'll attempt a reply based on what I assume to be the issue, and we'll move forward as best we can.
Since the only way a call to a member function can be made is to "know" the target object type, and to have an instance of it, upon which to base the call. We've covered this above, but it resolved to this form:
Code:
(*obj.*theMemFuncPtr)();
Where obj is a shared_ptr to the target object, and theMemFuncPtr is a pointer to a member function of the target object.
A generic object that can call such would have to be created with the target object in mind, as in:
Code:
shared_ptr<CommandObject<TargetObject> > cp( new CommandObject<TargetObject>( to, &TargetObject::func_to_call );
Where "to" itself is probably a shared_ptr<TargetObject>;
The CommandObject likely, then, also has a shared_ptr<TargetObject>, which I represented as obj in the previous code example.
Maybe it's because all of this is clear to me that I don't yet understand what the question really is, which is why I'm simply replying with a series of declarations, reasserting what I know is required.
Essentially this is a "manual" implementation object reflection of selected functions to be called. The reflection is implemented as a generic command object.
It appears you question has to do with the appropriate creation of a command object in concert with the creation of the object itself.
In my view the two can be separate if you like, as long as you use a shared_ptr<TargetObject> as the representative of the object to be called (which simplifies ownership/scope).
I have written/used systems where the command object uses a raw pointer to the target object, and as long as you can guarantee the target object will remain in scope, this is workable, just not quite as reliable - like any raw pointer usage.
There seems to choice in my view to fashioning the command design as a base class (probably non-template) with a derivative template class used to accept the target object and the function pointer assignment.
If you're concerned about the fact that template parameters are required, this is because template parameters can't be deduced by context for class creation. The can be deduced for a template function.
Therefore, you can create a non-member template function that adapts to the target object in question....something like this:
Code:
shared_ptr<CommandBase> = CreateCommand( to, &TargetObject::func_to_call );
CreateCommand is a factory, therefore, which adapts to the type of "to" - I assume to be a shared_ptr<TargetObject>, but it could be a TargetObject instance or pointer, depending on your storage strategy.
CreateCommand would be a template function - it's purpose is simply to adapt to To based on context, producing the appropriate template derivative of CommandBase to wrap around a TargetObject function call.
CommandBase would therefore have a generic virtual function, perhaps "DoIt" or "CallBack" - whatever you like, which is likely pure virtual, for which the template derivative of CommandBase would be ready to make the appropriate function call.
Let me know where I'm not understanding the specific concerns.
We've worked out that I was unaware of the shared_ptr's ability to handle different related types - and I'm not sure I've helped just yet.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
August 3rd, 2009, 12:39 AM
#11
Re: Smart Pointer Map Lookup
Yes, sorry about the thread drift.
Quote:
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.
I'm not entirely sure I do understand the question.
This is not your fault. I understand that and not need to blame yourself.
You have told me that in order to call a member function which required a object to call it.
Hence, generic command object has compose the target object to call. Do i correct ?
shared_ptr<CommandObject<TargetObject> > cp( new CommandObject<TargetObject>( to, &TargetObject::func_to_call );
Where "to" itself is probably a shared_ptr<TargetObject>;
The CommandObject likely, then, also has a shared_ptr<TargetObject>, which I represented as obj in the previous code example.
Essentially this is a "manual" implementation object reflection of selected functions to be called. The reflection is implemented as a generic command object.
Are you talking about the template metaprogramming techniques rreflection? Not really understand here.
It appears you question has to do with the appropriate creation of a command object in concert with the creation of the object itself.
In my view the two can be separate if you like, as long as you use a shared_ptr<TargetObject> as the representative of the object to be called (which simplifies ownership/scope).
Yes, this is correct. I just wonder how to relate the creation of object to appropriate command.
If you're concerned about the fact that template parameters are required, this is because template parameters can't be deduced by context for class creation. The can be deduced for a template function.
Therefore, you can create a non-member template function that adapts to the target object in question....something like this:
Code:
shared_ptr<CommandBase> = CreateCommand( to, &TargetObject::func_to_call );
CreateCommand is a factory, therefore, which adapts to the type of "to" - I assume to be a shared_ptr<TargetObject>, but it could be a TargetObject instance or pointer, depending on your storage strategy.
CreateCommand would be a template function - it's purpose is simply to adapt to To based on context, producing the appropriate template derivative of CommandBase to wrap around a TargetObject function call.
CommandBase would therefore have a generic virtual function, perhaps "DoIt" or "CallBack" - whatever you like, which is likely pure virtual, for which the template derivative of CommandBase would be ready to make the appropriate function call.
I will try to works on it. This seems to be a better approach than my manual vtable lookup appropriate. This approach using generic command object that compose target object to call.
EDIT:
Question:
1. Does this method can extend to array of target object member function ?
We've worked out that I was unaware of the shared_ptr's ability to handle different related types - and I'm not sure I've helped just yet.
This is OK. We are not the GOD. I really appreciate your help. I seldom found such a helpful in forum.
By the way, thanks for your help.
Last edited by Peter_APIIT; August 3rd, 2009 at 12:56 AM.
Thanks for your help.
-
August 3rd, 2009, 01:36 AM
#12
Re: Smart Pointer Map Lookup
My code below:
Code:
abstractHumanPtr::HumanPtr thePtr = theUserCreator.createUser();
Human* targetCommander = commandFactory(thePtr);
Commander<targetCommander> asd;
abstractHumanPtr::HumanPtr is a boost::shared_ptr<Human> in a class.
Error Message is 'targetCommander' is not a valid template type argument for parameter 'T'.
Code:
template <typename T>
T* commandFactory(boost::shared_ptr<T>& targetObject)
{
return targetObject.get();
}
template <typename T >
class Commander : public genericCommander
{
private:
T targetObject;
public:
Commander();
~Commander();
void ExecuteSignalCallBack();
};
class genericCommander
{
public:
genericCommander();
virtual ~genericCommander();
virtual void ExecuteSignalCallBack() = 0;
};
How to cope with this solution to handle array of member function for target object ?
Thanks for your help.
Thanks for your help.
Thanks for your help.
-
August 3rd, 2009, 08:33 AM
#13
Re: Smart Pointer Map Lookup
You have told me that in order to call a member function which required a object to call it.
Hence, generic command object has compose the target object to call. Do i correct ?
Yes, the 'real' or complete object that calls a function by member function pointer will have to fully 'know' the object on which to make the call.
We have a very minor language complication (I apologize, I'm a typical mono-lingual American, though I studied French for 2 years and my wife is Colombian, it just seems there so little time....).
If by "command object has compose the target object" - you mean the command object must fully 'know' the target, yes. If you're asking here if the command object must be the one to create the target - that can go either way - but at the point of creation of the command object, the child most type of the target object must be used.
For example, assuming CommandBase is the non-template generic, Command<T> is the template child....
shared_ptr<Staff> spf( new Staff );
shared_ptr<CommandBase> cp = new Command<Staff>( spf, ... );
If the target function is in Staff.
shared_ptr<Human> sph( new Staff );
shared_ptr<CommandBase> cp = new Command<Human>(spf, ...);
is fine if the target function is in Human.
Storage of the command can be by CommandBase. The child Command<T> would store a shared_ptr (or whatever you like) to the target object. Virtual function solves any "question" remaining.
This design is entirely generic - can call member functions of any object, not just human types.
Are you talking about the template metaprogramming techniques rreflection? Not really understand here.
Well, yes. The pointer to member function is the only technique available for runtime reflection. Any general reflection system would have to use that, or it would have to be external to the compiler (the way debug information does this for the debugger's use).
It may not have occurred to you because the purpose here is to call functions, we're thinking in terms of the command pattern.
What the literature doesn't make clear is that the command pattern requires reflection - you have to be able to "know" functions in a target by some description (even if that's an enumeration, a list - but it could be a map selected by name or something), which is the general idea of reflection.
The same technique can apply to member data, which makes it more obvious that the subject is reflection.
In other words:
Code:
class TargetObject
{
private:
int aninteger;
public:
void afunc();
};
int TargetObject::*a1 = &TargetObject::aninteger;
void (TargetObject:*f)() = &TargetObject::afunc;
In other words, if I create a container with a collection of these kinds of constructs, or even another object with these pointers (a1 and f), I an implementing reflection of TargetObject.
Most people would think of reflection as a "map" of the entire object, and in most situations it is - but selective or partial reflection is still the same concept - we're able to access members (data or functions) form an external means, perhaps even indexing members by a string (a name or key).
This isn't exactly meta-programming - that's a technique whereby we control the compiler at compile time - the result is usually not executable code, but code executed within the compiler.
Reflection is a runtime concept - offering the ability to use, inspect, inquire and therefore stream or otherwise use an object from a perspective "outside" the object.
That's basically what command objects are doing - operating an object (calling a member function) from an external means.
Yes, this is correct. I just wonder how to relate the creation of object to appropriate command.
Ok, now I'm able to focus more on that point - in a moment.
Does this method can extend to array of target object member function ?
Sure, but let me drift a bit on that.
In our conversations I've seen your interest in something like:
Code:
class Command<T>
{
private:
shared_ptr<T> op;
void ( T::*memfptr[10] ) ();
};
And this works, it assumes all of the target functions have the same signature, and only one shared_ptr<T> is required for all of them.
It can be simpler to deal with if that is
Code:
class Command<T>
{
private:
shared_ptr<T> op;
void ( T::*memfptr ) ();
};
class CommandList<T>
{
private:
Command<T> clist[10];
};
But, of course, that means there's also a shared_ptr<T> for each command.
If there's just 10 of these, and you have perhaps 4 or 5 target objects, that implies perhaps 50 shared_ptr<T> involved - and that's not terrible. If it provides leverage, it takes a bit more space, a little more time - only at creation - and it may simplify creation and thinking.
That can also be....
Code:
class Command<T>
{
private:
void ( T::*memfptr ) ();
void Callback( shared_ptr<T> &o ) { (*o.*memfptr)(); }
};
class CommandList<T>
{
private:
shared_ptr<T> op;
Command<T> clist[10];
public:
virtual void CallCommand( int i ) { clist[i].Callback( op ); }
};
...that's pseudo code - I might be off a typo or something.
The idea is that the CommandList might own the shared_ptr<T>, so there's only one target object, and there's a list of Command<T> holding function pointers.
The point here is that creation of the list of Command<T> might be conceptually easier than an array of member function pointers.
For me to better understand the design you need, we need to clarify how you want to call these functions.
For example, how do you want to specify what function to call? Are you selecting by number (or enum)? Maybe a string as a key?
How about the target object selection? Do you want to call the target based on number (or enum)? Could also be by a name...
Answers to these questions help define the internal structure and the interface you require, which in turn may dictate how these things are fashioned.
For example:
Code:
Commander.Call( "Jane", "Calc Vacation Pay" );
or
Command.Call( jane, calc_vacation_pay );
In the latter, where jane is a shared_ptr<Staff> and calc_vacation_pay is from an enum of available functions or something similar, or an integer representing something similar.
There are numerous variations, including something like:
Code:
Commander.CallAll( calc_overtime_pay );
Which might perform a calculation for all objects known to the commander.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
August 4th, 2009, 04:02 AM
#14
Re: Smart Pointer Map Lookup
OK. I just want to call using integer only.
Code:
shared_ptr<Human> sph( new Staff );
shared_ptr<CommandBase> cp = new Command<Human>(spf, ...);
I don't understand this.
My Question :
1. What is the usage of command factory ?
2. How to initialize the command list member command with a sequence of command which can handle different type ?
3. What is the type to command list or commander ?
4. What is the usage of GenericCommander base class since there is no polymorphism involved ?
My code so far :
Code:
abstractHumanPtr::HumanPtr thePtr = theUserCreator.createUser();
CommandList<Human> contObj(thePtr);
template <typename T>
T* commandFactory(boost::shared_ptr<T>& targetObject)
{
return targetObject.get();
}
class GenericCommander
{
public:
GenericCommander();
virtual ~GenericCommander();
virtual void ExecuteSignalCallBack() = 0;
};
template <typename T>
class Commander : public GenericCommander
{
private:
void (T::*MemberFuncPtr)();
public:
Commander();
~Commander();
void ExecuteSignalCallBack(const boost::shared_ptr<T>& );
};
template <typename T>
Commander<T>::Commander()
{
}
// =========================================
template <typename T>
Commander<T>::~Commander()
{
}
// =========================================
template <typename T>
void Commander<T>::ExecuteSignalCallBack(const boost::shared_ptr<T>& commandCaller)
{
(*commandCaller.*MemberFuncPtr)();
}
template <typename T>
class Commander;
template <typename T>
class CommandList
{
public:
typedef boost::shared_ptr<T> objectPtr;
private:
objectPtr targerObjectPtr;
Commander<T> cont[15];
public:
CommandList();
explicit CommandList(const objectPtr&);
~CommandList();
void CallCommand(int );
void CommandInit();
};
// =========================================
template <typename T>
CommandList<T>::CommandList()
: targerObjectPtr(objectPtr), cont(Commander<T>())
{
}
// =========================================
template <typename T>
CommandList<T>::CommandList(const objectPtr& userTargetObjectPtr)
: targerObjectPtr(userTargetObjectPtr)
{
CommandInit();
}
// =========================================
template <typename T>
CommandList<T>::~CommandList()
{
}
// =========================================
template <typename T>
void CommandList<T>::CallCommand(int choice)
{
cont[choice - 1].ExecuteSignalCallBack(targerObjectPtr);
}
// =========================================
template <typename T>
void CommandList<T>::CommandInit()
{
}
void CommandInit(); used to initialize list of command for the target object.
Thanks for your help.
Last edited by Peter_APIIT; August 4th, 2009 at 04:24 AM.
Thanks for your help.
-
August 4th, 2009, 10:52 AM
#15
Re: Smart Pointer Map Lookup
Code:
Code:
shared_ptr<Human> sph( new Staff );
shared_ptr<CommandBase> cp = new Command<Human>(spf, ...);
I don't understand this.
This and the example just before it simply indicate that if you're going to prepare for a call to a function in the Staff class, the Command that's fashioned has to be a Command<Staff>, however (this snippet) points out that even if the object IS a Staff, if the target function is really in Human (it's base), the command can be fashioned Command<Human>, if it's convenient.
1. What is the usage of command factory ?
The command factory idea is simply a simpler interface for making commands. It can help make the registration of commands a little easier. Template class instantiations require full types - the compiler can't deduce based on context.
Command<TargetObject> c( o, &TargetObject::function );
However, a template function in the command target, or some other template function (non-member) can deduce based on context, so that can be made a little simpler. If (as is likely) the Command<T> is stored by some non-template base (CommandBase for example), the factory might be used thus:
shared_ptr<CommandBase> = CreateCommand( o, &TargetObject::function );
The template function "CreateCommand" (it could be non-member, it could be static, it could be a template function member of a commander class) can deduce the template parameter for creating a Command<T>, the base of which is something like CommandBase.
Code:
2. How to initialize the command list member command with a sequence of command which can handle different type ?
"Different type" - I'm not sure I understand; I think this can mean a different type of target object who's member function is to be called, it could mean the function signature is a different type (returns something, takes a parameter).
For the first....there's a second question to ask. You said you want to call by number. That's fine, what does this number represent?
It could be that there is a command list such that a single integer represent a command call - that command call "knows" the target object and function to be called.
On the other hand, it could be that the command list is structured by type - such that you must specify two integers, an object type and a function ID - one integer represents the target object type to call, the other the function within that object.
Both of these imply that for any command there is only one target object, and the command knows that target object.
This further implies that if there were, say, 5 target objects of the same type, and one function to be called, there would be 5 command objects, each one representing the same member function for each of the 5 target objects. This may be appropriate if the population of target objects is always small.
On the other hand, it is entirely reasonable to want a command system that allows you to select functions for any target object. This target object can be supplied at the time the call is required (this is more complex and flexible - I don't yet sense this is your interest).
In any event, if you form a command list based on a non-template base (CommandBase for example), then storage is from that common viewpoint (the container need not know the target object types, they can be a mixture of any target objects).
A virtual funtion in CommandBase (likely pure virtual) suffices. The child template Command<T> responds, know the type and likely the actual object upon which the call is based.
3. What is the type to command list or commander ?
Assuming CommandBase is a simple non-template with a virtual "callback" function - and the "real" object instantiated is a Command<T> derived from CommandBase, the command list could be a simple as...
vector<shared_ptr<CommandBase> > a;
...The shared_ptr means the "real" type of each entry can be virtual. You can't store virtual objects in
vector<CommandBase>....
The vector can't accept Command<T> in such a container.
I envision the commander is a class which owns the command list (it would be a member of that class), and may provide other conveniences for making the generic calls, registering - whatever general operations represent the concept of commands.
4. What is the usage of GenericCommander base class since there is no polymorphism involved ?
First, there is polymorphism there.
However, I've been a bit careless with names. I respond occasionally on a laptop without my notes (I have, for example, a VS2008 project of your name with some examples I've used to proof some of the code snippets, but at the moment I'm on a laptop attending my son's swimming lesson, my notes aren't with me, and I'm typing in a stream of thought - so my choice for class names are a whim).
CommandBase == GenericCommander
Command<T> == Commander<T>
You'll note there's a virtual function in GenericCommander called ExecuteSignalCallback. This is a generic interface.
vector<shared_ptr<GenericCommander> > commandlist;
This list would not "know", from this perspective, what target objects or functions are involved. It can do this....
commandlist[2]->ExecuteSignallCallback();
The child version of that function, in Commander<T>, "knows" the type of the object being called.
There's something missing though (Did I type Commander<T> in your post?)....
I don't see the function body there.....it would need a shared_ptr<T> upon which to base the function call...
Oh, I see - you titled it - your code so far...
Out here in the bright sun, a laptop screen isn't easy to read ....
I'll check back later today to see if I've missed something significant.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|