|
Hey everybody,
Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;
void Do()
{
(*onClick) ();
}
};
void ok()
{
printf("OK\r\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");
R r;
r.onClick = &ok;
r.Do();
...
Just runs. Function pointer works..
But if I try to point a NON-STATIC function of a class.. well cant do that! I need to pass class instance also.. But dunno if there's a way to do that without templates.
So any idea how to do that without using template?
To make it clear:
class A
{
public:
void run(void);
};
class R
{
public:
typedef void (*Method)();
Method onClick;
void Do()
{
(*onClick) ();
}
};
void ok()
{
printf("OK\r\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");
A a;
R r;
r.onClick = &a.run;
r.Do();
...
|
|
|
|
|
There is a difference between a regular function pointer as you have declared in R, and a "pointer to a member function," which is what you want in the last code example.
The syntax is quite cryptic, and I don't recall what it is, but if you search for "pointer to member function," I'm sure you'll come up with it.
|
|
|
|
|
A non-static method pointer is the same as any function pointer that needs parameters - you need to tell the caller what those parameters are.
So, you could do this:
class R
{
public:
typedef void (A::*Method)();
struct MethodCall { Method fn; A obj; };
MethodCall onClick;
void Do()
{
Method m = onClick.fn;
A& a = onClick.obj;
((a).*(m))();
}
};
int main(int argc, char* argv[])
{
A a;
R r;
r.onClick.obj = a;
r.onClick.fn = &A::run;
r.Do();
}
But then if you wanted to use ok as a handler as well, you'd need to add a separate data member for that.
Getting around all that is the raison d'etre for Boost.Function[^] (also in std::tr1::function in VC2008, I believe). With that (and a smidgen of Boost.Lambda[^]), I'd write your onClick handler like this:
#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
class A
{
public:
void run(void) { std::cout << "A::run\n"; }
};
class R
{
public:
boost::function<void()> onClick;
void Do()
{
onClick();
}
};
void ok()
{
std::cout << "ok\n";
}
int main(int argc, char* argv[])
{
A a;
R r;
r.onClick = ok;
r.Do();
using namespace boost::lambda;
r.onClick = bind(&A::run, var(a));
r.Do();
}
If you then want multiple handlers, Boost.Signals[^] is very useful as well!
[edit]It would be remiss of me not to point out that Boost.Function is compatible with the STL binders such as mem_fun[^] - but as Boost.Lambda is so much cooler, I hope you'll forgive me [/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
|
|
|
|
|
OK I forgot to mention the most important thing
I want to point my function at run time. I mean it should be any kind of function pointer which accept this. So this is not acceptable for me &A::run...
I do not need boost for that (this will do the job if I already knew the class):
class SomeClass;
typedef void (SomeClass::* SomeClassFunction)(void);
void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {
(pClass->*funcptr)(); };
Seems like there's no way...
|
|
|
|
|
dehseth wrote: I do not need boost for that
Maybe not - but it sure makes things a lot easier And not just for function pointers!!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
|
|
|
|
|
You don't like polymorphism, do you (i.e. why do you want to do that, cannot you find an OOP way to accomplish your needs)?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Stuart,
Excellent answer, as usual. I have one question:
You gave the actual function call as:
((a).*(m))();
Why do we need the parenthesis around a ?
Why can we not write:
(a.*(m))(); ?
|
|
|
|
|
I can never remember the syntax you need for a member function pointer call - so I kept putting in brackets until it compiled I just happened to put the brackets round a before the ones that really mattered!!
[edit]
Richard Andrew x64 wrote: Excellent answer, as usual
PS - thank you for the compliment - I tries me best, Guvnor!
[/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
modified on Monday, March 2, 2009 4:11 PM
|
|
|
|
|
Very nicely written, Stuart. My 5 for you.
It is a crappy thing, but it's life -^ Carlo Pallini
|
|
|
|
|
There are three reasons you can't do this the way you think it should work:
First &a.run is not the right way of getting a pointer to a class function, it is &A::run.
Second you can't convert from your Method type above to &A::run.
Third you can't execute a non-static method of a class unless you have an instance of that class (and this looks quite normal because we have to know which instance it is whose method we want to execute, non-static method have no meaning without an instance)
This is how you would write it using your way of thinking:
class A{
public: void run(void);
};
class R{
public:
typedef void (A::*Method)();
Method onClick;
void Do(A* a)
{
(a->*onClick) ();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");
A a;
R r;
r.onClick = &A::run;
r.Do(&a);...
}
As you can see however there is nothing much useful to generalize, so the above code is just hiding something for no apparent reason. But you needed an answer
You can't create a pointer for one class non-static method and use it as a pointer to another class method.
|
|
|
|
|
The reason this is so is that method does not know anything about the instance that calls it. The instance pointer (this) is resolved at the moment of method call. This:
C c;<br />
c.method();
is executed using always one and the same address of the method but the class instance pointer ( this-> ) is passed for example as the first hidden parameter (which is hidden from us) like this
method(&c)
or the instance pointer (&c) is moved into ECX register first and then method() is called where each this-> is then referred by the content of ECX.
You can't avoid this problem even with boost or any other library.
|
|
|
|
|
If you are ready to make a slight design change this is what you can do and to get something fairly useful
class T
{
public:
virtual void run() = 0;
virtual void run1() = 0;
};
class A : public T
{
public:
void run(){
};
void run1(){
};
};
class F : public T
{
public:
void run(){
};
void run1(){
};
};
class R{
public:
typedef void (T::*Method)();
Method onClick;
void Do(T* t)
{
(t->*onClick)();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
F f;
R r;
r.onClick = &T::run;
r.Do(&a);
r.Do(&f);
r.onClick = &T::run1;
r.Do(&a);
r.Do(&f);
...
modified on Monday, March 2, 2009 5:57 PM
|
|
|
|
|
|
Sounds like a homework problem.
Anyway, could you describe exactly what the difference between the two formats is?
|
|
|
|
|
You need to state exactly what type of format or organising structure you are trying to acheive.
|
|
|
|
|
Are you trying to just get rid of the duplicated record?
|
|
|
|
|
It's my problem man.I don't what rid problem and what he want to do..If you have some idia then plz help me
|
|
|
|
|
i need remove duplicate values..
|
|
|
|
|
You can use "std::unique" algo, but you will have to design your own class with overloads to support it.
Example[^]
He never answers anyone who replies to him. I've taken to calling him a retard, which is not fair to retards everywhere.-Christian Graus
|
|
|
|
|
Then in any environment, you need to qualify what you wish to discard.
You need to place a field (that you specify) into a list box and disallow
the duplication of a matching field. If the field or database.component is
new then allow the record to be copied to a new file.
At the end (after testing) simply replace your old file with the new one.
I'm assuming your running a few thousand records.
|
|
|
|
|
Ric Ashton wrote: I'm assuming your running a few thousand records.
Don't be so generous. This is obviously a homework assignment.
|
|
|
|
|
1- create a structure (or class) that contains the fields for each record ; create/use a collection that holds your records
2- in a loop :
3- read one line of the file, knowing that you know the format, you can skip unwanted lines.
4- skip line if unwanted; if line contains (is?) "============" and it's the first one, then you know it's a
new record.
5- read the next few lines to fill a record.
6- look in your collection to see if new record is already there; if it's not there, add it to your collection.
7- once you've read all the lines,
8- write back the data line-by-line in a new file.
(steps 5,6 can be optimized to not have to create a new record until you've find if the item is not in the collection).
This signature was proudly tested on animals.
|
|
|
|
|
Thanks sir your logic is to much sound.Can you give me some dummy code.Plz help me
|
|
|
|
|
I will not give you code (dummy or not); I want you to try to come up with a solution based on the suggestions we've given you.
Once you've tried one, two, or even more solutions to your problem (which sounds like a homework), and you still
have problems, then we will gladly be of help of precise problems you can still have.
It can be also easier to ask questions to your teachers and/or teaching assistants and/or computer lab assistants;
or even fellow students.
This signature was proudly tested on animals.
|
|
|
|
|
The first order of business would be to read the data into some sort of data structure. Until you can get that far, eliminating duplicates is irrelevant.
"Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
|
|
|
|