수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1620982
  • Today | 362
  • Yesterday | 482

1 Articles, Search for 'Function Pointer'

  1. 2007/07/30 Function Pointers (1)
Programming/C++2007/07/30 10:16

Function Pointers

출처 : http://www.devarticles.com/c/a/cplusplu ··· art-1%2F

In this first of a three-part series of articles, J. Nakamura covers regular function pointers. These pointers allow you to access the code you write for your applications in the form of functions.

Introduction

In a previous series of articles named “Pointer Perfect,” I looked at how data stored in computer memory is accessible through pointers. The code you write for your application in the form of functions (these can be global or class member functions) is very much accessible through pointers in the same way, and I will introduce you to the syntax and usage of these function pointers in this article.

Function pointers are great for implementing callbacks and are very useful when you want to introduce late binding in your application. They help you parse configuration files, help you read protocols and can help you store a function call in an object when you want to delay or record the call (very useful in an undo/redo system).

Most C++ books treat function pointers superficially, which is very unfortunate; maybe this is because their syntax looks a bit weird when you first start using them. I hope to be able to convince you that the right function pointer at the right moment in the right place will make your code clearer, cleaner and easier to understand. Once you get past the odd syntax and come to understand the power of calling functions through pointers, a whole new level of abstraction will open up to you.

A Quick Example

There is nothing like a quick example to take you straight to the heart of a topic. Here is a simple code example that uses a function pointer.

// main.cpp

#include

int IncOne(int var) {

return ++var;

}

int main(int argc, char *argv[]) {

// creating pointer to function

int (*inc_one)(int) = &IncOne;

// use the function the standard way

int result = IncOne(1);

(void)printf(“result is: %d\n”, result);

// utilize the function pointer

result = inc_one(1);

(void)printf(“result is: %d\n”, result);

return 0;

}

When you run this simple example, you will notice that both times the result printed is "2" -- as expected, of course. So what has the compiler come up with for us? Let’s take a peek into the debugger at the value stored in inc_one.

int (*inc_one)(int) = &IncOne;

00411A9E mov dword ptr [inc_one],offset IncOne (411523h)

It holds the address 0x00411523, and looking at the memory at that position we find the following line:

0041126C jmp IncOne (411A40h)

Our code is ordered to jump to 0x411A40, where we of course will find the code of our IncOne() function:

int IncOne(int var)

{

00411A40 push ebp

00411A41 mov ebp,esp

...

}

So what does the assembly in the debugger look like when we make a normal function call to IncOne() ?

int result=IncOne(1);

00411AA5 push 1

00411AA7 call IncOne (41126Ch)

Hold on! The debugger tells us that we go to 0x0041126c, where we are made to jump to IncOne (0x00422A40). So what happens when we call the function using the function pointer inc_one?

result=inc_one(1);

00411AC3 mov esi,esp

00411AC5 push 1

00411AC7 call dword ptr [inc_one]

Exactly the same thing! The content of inc_one is 0x0041126C, which, when called, makes our code jump to IncOne (0x00422A40), where the function is executed. This basically covers the whole concept of function pointers. All that is left now are the many (strange) forms in which they can appear.

The function pointer in our quick example points to the address of an ordinary C function. There are no special considerations for us to make in this case.

The code you compile to create your executable takes up a certain space in the computer's memory, where your data and functions will reside during its execution. Just like the data accessible through pointers, we have seen that functions are accessible in the very same way. The only thing a compiler has to know is how to interpret the address to which a pointer is pointing; this is where things can become slightly confusing, as we run into the often odd syntax of function pointers.

Defining and Using Regular Function Pointers

Just like regular pointers, function pointers are variables that need to be declared and defined. In the quick example you saw that inc_one is our function pointer variable, holding the pointer to a function that returns an int and that takes an int as a parameter.

To give you another example, if you declare the following function:

void AnotherFunction(std::string const &argument, float value);

Then you would assign the address of this function to a function pointer variable like this:

void (*fncptr)(std::string const&,float) = &AnotherFunction;

Hopefully you can see a pattern emerging here. The function declaration is basically being repeated, with the function name replaced by a "*varName," and only the types of the parameters are named. The retrieval of the address of a function works just like the address retrieval of a variable; you can use the address dereference operator "&."

Personally, I find the above demonstrated way of defining a function pointer a bit hard to read. When you need more variables to hold pointers to the same function, it can become quite laborious and sensitive to typing errors, too. Not to mention the fact that when the function definition changes, you would have to chase down and change every function pointer pointing to the changed function as well.

So here we will find the use of the typedef keyword very useful:

typedef int (*FncPtr)(int);

When we stick to the example, we can replace the add_one definition with:

FncPtr inc_one = &IncOne;

So you see that it is really easy to declare function pointers. Just as with normal pointers, you either use the pointer directly or you use it by dereferencing the pointer explicitly:

int result1 = inc_one(1);

int result2 = (*inc_one)(1);

Making the function call through a pointer or just the plain way will yield not very noticeable differences. It's quite nice to be able to abstract a function call into a variable, isn’t it?

Passing a function pointer as an argument to a function is quite essential when you want to implement callback functions. Although we won’t be looking at the implementation and usage of callback functions until later on, let’s take a look at the syntax right now.

The benefit of passing a function pointer as an argument to another function lies in the fact that this allows us to dictate which function that other function has to execute. There is nothing really different from what we have seen before, except for the fact that it looks slightly different.

// a raw declaration

void foo(int (*FPtr)(char const*));

// using a typedef

typedef int (*FuncPtr)(char const*);

void foo(FuncPtr fptr);

Did you recognize the function passed in through a pointer to foo? It is a function that takes a char const pointer as an argument and returns an int.

int func(char const *param);

Another tricky syntax is the raw declaration of a function that returns a function pointer.

// a raw declaration

int (*getFuncPtr1(int ID))(char const*);

// using a typedef

typedef int (*FuncPtr)(char const*);

FuncPtr getFuncPtr2(int ID);

It is pretty clear that the usage of a typedef clears things up a lot in this case. Did you notice that getFuncPtr1 returns a pointer to the same function (func) we had actually already declared before?

Function Pointer Arrays

Since they are stored as variables, it is possible to have an array of function pointers -- but mixing the two guarantees a confusing syntax when you are going to do it all "raw." The beauty of function pointer arrays comes from the fact that you can bind functions to indices, which in turn could come from an enumeration you declared earlier on. This way you can create statements like: int res = (*opArray[PLUS])(a,b);.

// a raw declaration

int (*funcArray1[10])(char const*);

// using a typedef

typedef int (*FuncPtr)(char const*);

FuncPtr funcArray2[10];

// an example assignment

funcArray1[0] = funcArray2[5] = &func;

// example usage

int result1 = (*funcArray1[0])(“a test”);

int result2 = (*funcArray2[5])(“and then some”);

Let’s try to make this even more interesting and take a look at how we define pointers to templated functions. First we need a templated function to point at:

template T Inc(T var) {

return ++var;

}

Unfortunately the C++ standard doesn’t allow us to make template declarations in the scope of function bodies, so we cannot define a pointer to a templated function like this in main():

template T (*IncPtr)(T) = &Inc;

It is important to understand how compilers instantiate templates as well. They only instantiate templated code when it is needed, and they will not even detect a syntax error if the templated function is never called (a lot of clever and tricky meta template programming makes good use of this compiler behavior). It doesn’t make sense, and hopelessly complicates things for compiler builders, when you try to declare a templated pointer at a point where the compiler is hard at work instantiating code (as in function bodies). When you make a function call, data is going to be moved onto the memory stack, and the compiler needs to know which parameters to use. By trying to template the pointer, we are denying it that very information, and it won’t be able to continue the compilation.

So what is it we can do with the templated function Inc() we have? When we tell the compiler how we are planning to use the function, defining a function pointer to it works fine:

int main(int argc, char *argv[]) {

// Use Inc to increase an integer

int (*incN)(int) = &Inc;

int nres = incN(1);

(void)printf(“result is: %d\n”, nres);

// Use Inc to increase a float

float (*incF)(float) = &Inc;

float fres = incF(1.f);

(void)printf(“result is: %f\n”, fres);

}

When you run this example you will see that it works fine.

So is there no way we can delay the type definition of the function we want to define a function pointer to? Well, there is one location where this is possible: inside a templated function:

template

T Foo(T var) {

T (*incPtr)(T) = &Inc ;

return incPtr(var); }

Adding the following line to our example shows that it works fine:

int foores = Foo (1);

(void)printf(“result is: %d\n”, result);

When you think about it, it actually makes sense, because by the time Foo is instantiated, typename T is known by the compiler, and it has no problem instantiating the function pointer to Inc.

There is much more to function pointers than actually meets the eye. In the next article I will take a look at class member function pointers and place them in the same context I have done with the regular function pointers in this article. Finally, in the third article you will find a callback implementation example, function pointers mixed with calling conventions and an introduction to C++ functors.

In the previous article, Jun Nakamura introduced you to the use of regular function pointers, but when you write C++ code, you will be interested in C++ class member function pointers too. It is time to look at how to declare pointers to the members of classes you write for your applications.

Class Member Function Pointer Syntax

The declaration of a C++ member function pointer is a bit trickier than the regular ones we have seen so far and I have to say they look pretty strange as well.

You might wonder what the use of a member function pointer is. One of the uses I have found for it is in a protocol definition I wrote for a server application. The protocol is described in a static struct, where string messages are tied to pointers to the member functions in the protocol class that can handle specific messages. This ties the abstract knowledge of the messages to the lower functionality in the protocol class. Here is a section of that code:

static struct RQRSTable {
  unsigned int         privileges;
  ProtocolImpl::RQType requestType; 
  HandleFunc           function;
  string               header;
} rqrsTable[] =
{
// LOGIN -------------------------------------------------
// (CLT)RQ::LOGIN::<`username(str)`>
//   example RQ::LOGIN::`Jun`
  {
   Read | Write | Admin,  // privileges
   ProtocolImpl::Request, // request type 
   &ProtocolImpl::login,  // function
   “CLT::RS::LOGIN”       // header
  },
  ...
};

By now you should be able to see that &ProtocolImpl::login is the function pointer stored in this struct. It describes which function has to be called for which header. A simple loop in a parser function can extrapolate the header from a message, look it up in the struct and execute the attached function by making a call to
rqrsTable[idx].function().

Though a function pointer to a member function looks a bit more complex, it shouldn’t be too difficult to understand how they work now. Here is the function pointed at by the example:

bool ProtocolImpl::login(string const &msg, RQRSTable const *rt);

And this is the typedef I used to define the function pointer as used in the example struct:

typedef bool (ProtocolImpl::*HandleFunc)
                 (string const&, struct RQRSTable*);

It all doesn’t look that different from the regular function pointer syntax when you take a closer look at it. The main difference lies in the fact that you have to specify the class scope of the function pointer, so that the compiler understands that the function pointer is aimed at the member of a class.

Of course there are more ways to declare a member function in a class, so let’s use this simple class definition to try them out:

class MyClass {
public:
  MyClass() : m_value(0) {}
  void SetValue(int value) { m_value=value; }
  int GetValue() const { return m_value; }
  inline void InlineFoo() { (void)printf(“inlined\n”); }

static void foo(char const *msg, int value)
  { (void)printf(“%s %d\n”, msg, value); }
private:
  int m_value;
};

The function pointer comparable to the one used in the example struct is one that points to void MyClass::SetValue(int):

// raw declaration and assignment
void (MyClass::*svalue)(int) = &MyClass::SetValue;

// utilizing a typedef
typedef void (MyClass:*SValue)(int);
SValue svalue = &MyClass::SetValue;

So you see that the function pointer to a member function only needs ‘MyClass::’ in front of the variable name to declare it (which is probably the reason why it instinctively looks a bit weird). Member functions can have more identities than this one so let’s see how we define pointers to the other functions.

// raw declaration and assignment
int (MyClass::*gvalue)() const = &MyClass::GetValue;

// utilizing a typedef
typedef void (MyClass::GValue)() const;
GValue gvalue = &MyClass::GetValue;

A const member function pointer is defined the same way we have been declaring function pointers up to now: just add const.

// raw declaration and assignment
void (MyClass::*inlfoo)() = &MyClass::InlineFoo;

// utilizing a typedef
typedef void (MyClass::*InlFoo)();
InlFoo infloo = &MyClass::InlineFoo;

The function pointer above may come as a small surprise, because you would expect the code of an inlined member function to be pasted into where we normally would find the function call. However when you declare a member function pointer to an inlined function, the compiler creates a body for that function so that it can be executed when you call that member function pointer.

// raw declaration and assignment
void (*foo)(char const*, int) = &MyClass::foo;

// utilizing a typedef
typedef void (*FooPtr)(char const*, int);
FooPtr foo = &MyClass::foo;

Can you guess which member function is being pointed at by FooPtr without having to go back to the declaration of MyClass?

It is pointing at: ‘static void foo (char const * msg, int val );’ Again this may come a bit unexpected, but pointers to static member functions are declared just like the regular function pointers. And when you think about it… static member functions can be used just like regular functions, with them main difference being the fact that you have to provide the class scope (‘MyClass::’) when calling them.

Defining member function pointers is one thing; now let’s see how we use them. There are some specifics you have to be aware of when calling member functions in objects. Let’s write some code that tests the above defined member function pointers.

int main (int argc, char *argv[]) { =
  MyClass myclass;
  SValue svalue = &MyClass::SetValue;
  (myclass.*svalue)(0x1234);

  GValue gvalue = &MyClass::GetValue;
  int res = (myclass.*gvalue)();
  (void)printf(“result is 0x%d\n”, res);

  InlineFoo inlinefoo = &MyClass::InlineFoo; 
  (myclass.*inlinefoo)();

  FooPtr fooptr = &MyClass::foo;
  Fooptr(“result is: “, (myclass.*gvalue)());
}

It will generate the following output:

result is 0x00001234
inlined
result is: 4660

When you plan to use a member function pointer you will need an object of the class you are going to use it on. The syntax boils down to (myobject.*fncptr)(), where <MYOBJECT.> is the name of the instantiated class and <*FNCPTR> is the name of the used member function pointer.

How do member function pointers hold up in the face of Polymorphism? Will the function in a derived class be executed when we use a member function pointer containing the address of the baseclass function? Let me show you what I am getting at.

A typical way to make good use of polymorphism is to have a collection of base class pointers that are pointing to instantiated derived objects. To do this, you have to create the derived object and use the pointer to its baseclass:

class Base {
public:
virtual ~Base()=0;
virtual int foo() const=0;
};

class Deriv1 : public Base { public: int foo() { return 0; } };
class Deriv2 : public Base { public: int foo() { return 1; } };

// somewhere in your code
Base *ptr1 = new Deriv1;
int result = ptr1->foo(); // result will be 0

One of the great benefits of polymorphic classes is that you don’t have to be familiar with their implementation, only with their interface as it is declared in the baseclass. In the example above we know that there is a function called foo() but we don’t have to know what it exactly does. This can be a very useful concept for example in a game where there could be a list of game objects that all implement a run() function. The main game loop can call this run function on every game object, without having to know it is dealing with physics, A.I. or particle system objects. This also means you can add new game objects that implement different behaviors (and/or visuals) without having to make changes to the main code base.

So basically my question is: “When I use a member function pointer to Base::run() and use it on a Base* pointer that actually points to a derived game object… will the code in that game object be executed or will the code in the base object be executed?” A flipside question is whether it is possible to combine the member function pointer to Base::run() on a pointer (or reference) to a derived game object… thus not directly on Base itself. Let’s try this out with our Base and Deriv1 and Deriv2 example.

typedef int (Base::*BaseFooPtr)();
// ... later
BaseFooPtr fooptr = &Base::foo;
// ... test1 – try the BaseFooPtr on Base* to a Deriv1 object.
Base *baseptr = new Deriv1;
int result1 = (baseptr->*fooptr)();
// ... test2 – try the BaseFooPtr on a Deriv2 object.
Deriv2 myDeriv2;
Int result2 = (myDeriv2.*fooptr)();

Running this code you will find that member function pointers behave the same way you would expect normal function calls to behave in the face of polymorphism… answering both of my questions. The results are the same as when we wouldn’t have used a member function pointer but the regular functions calls instead. Thus result1 is 0 and result2 is 1!

It is very well possible that you want to pass a member function pointer to a function or return one from a function. We have seen that all we need to do is add the ‘MyClass::’ scope in front of the variable name, so lets look at how this translates to function parameters and return values. Let’s place the example function we’ve used before into class MyClass:

int MyClass::func(char const *param);

Here are some functions that accept a pointer to this member function:

// a raw declaration
void foo(int (MyClass::*FPtr)(char const*));

// using a typedef
typedef int (MyClass::*FuncPtr)(char const*);
void foo(FuncPtr fptr);

If you compare these function declarations with the ones in the previous article, you will see that indeed all you need to add is ‘MyClass::’. Declaring a function that returns a function pointer, we do the exact same thing:

// a raw declaration
int (MyClass::*getFuncPtr1(int ID))(char const*);

// using a typedef
typedef int (MyClass::*FuncPtr)(char const*);
FuncPtr GetFuncPtr2(int ID);

I honestly think that the raw declaration above (possibly combined with a couple of function pointers as parameters) is a good candidate for usage in an obfuscated C++ coding contest.

Do you understand the following function declaration?

char const* const ( MyClass::*FuncAt(
   void (MyClass::*Fptr1)(char, char),
   float (MyClass::*Fptr2)(int) ))(char const*, int);

Lets not even go there ;-) !

Member Function Pointer Arrays

Similar to the previous member function pointers described before; in order to create member function pointer arrays, we only need to add the class scope to the regular function pointer array declaration.

// a raw declaration
int (MyClass::*funcArray1[10])(char const*);

// using a typedef
typedef int (MyClass::*FuncPtr)(char const*);
FuncPtr funcArray2[10];

// initializing ome
funcArray1[0] = &MyClass::func;

// and finally making use of it
MyClass myClass;
int result1 = (MyClass.*funcArray1[0])(“a test”);

Now that we have seen the many forms function pointers can take, it is quite understandable that many C++ programming books treat this topic superficially. I hope I was able to shed some light in this rather shaded corner of the language and in the concluding article, I will show you the effect calling conventions have on function pointers, provide you with an example and introduce you to C++ functors.

In previous articles, Jun Nakamura introduced using regular function pointers, C++ class member function pointers, and declaring pointers to the members of classes. In this article, he writes about calling conventions, callback functions, and begins to talk about using functors.

There are many programming languages out there and a lot of them come with very useful libraries and APIs. It is possible to tie all these different libraries (coded in different languages) together in your main application.

Maybe you want to develop the user interface in Visual Basic, need a performance sensitive engine coded in C and C++ and have some legacy functionality of which nobody understands the implementation anymore running in Fortran. As you might have guessed, I have actually worked for a company that strung applications together that used libraries like these.

Different languages use different calling conventions because there are many ways to implement function calls on a computer. The main issue here is the order in which function parameters are passed to the function when it is called. These parameters are put onto the memory stack so that the function that is about to execute has access to them. The next issue is whether the caller or the called function will clean up these parameters.

Though I don’t want to go too deep into calling conventions, stacks etcetera, let me give you a small overview.

Alright, here is an overview of how different some Windows calling conventions can be (__pascal, __fortran and __syscall are no longer supported):

__cdecl
Argument Passing: right to left
Stack Maintenance: Calling function pops arguments from the stack
Name Decoration (C only): ‘_’ prefixed to function names (e.g. ‘_foo’)

__stdcall
Argument Passing: right to left
Stack Maintenance: Called function pops its own arguments from the stack
Name Decoration (C only): ‘_’ prefixed to function name, ‘@’ appended followed by the number of decimal bytes in the argument list. (e.g. ‘_foo@10’)

__fastcall (applies to Intel CPUs, this is the default calling convention for Borland)
Argument Passing: First two DWORD arguments are passed in ECX and EDX, the rest is passed right to left
Stack Maintenance: Called function pops its own arguments from the stack
Name Decoration (C only): ‘@’ is prefixed to the name, ‘@’ appended followed by the number decimal bytes in the argument list. (e.g. ‘@foo@10’)

thiscall (used automatically by C++ code)
Argument Passing: ‘this’ pointer put in ECX, arguments passed right to left
Stack Maintenance: Calling function pops arguments from the stack
Name Decoration: None

You see that there are many ways leading to Rome, and this is just on a Windows machine. What is interesting for this article though, is how we declare a function pointer to the following function definition:

void __stdcall Convention(int value, char const *string)
{
  (void)printf(“%d, ‘%s’\n”, value, string);
}

Again, the answer here is simple; we simply integrate the calling convention we need into the function pointer declaration:

void (__stdcall *ConvPtr)(int, char const*) = &Convention;

The principle remains the same whether it is a member function, a function argument, etc. Just bolt what you need into the declaration.

When your linker is giving you errors that it cannot resolve external symbols while you know that you are linking with the correct libraries; be sure to check which calling conventions are being used.

One of the great concepts of function pointers is that of the callback function. As you have seen it is pretty easy to transform the identity of a function into a pointer, which can point to different implementations of a function with that same identity (they all return the same type and accept the same type of parameters in the same sequence). This means that as long as you create a function that returns the right argument and takes the right argument(s), you can insert your own functionality into other people’s code.

An excellent example of this is a library that can read and render Macromedia Flash files, but has to run on a lot of different platforms including game consoles. Since memory management is radically different from console to console (there are no malloc or free functions standard on a Nintendo GameCube), the library allows you to register your own memory allocation and deallocation callback functions with it. Whenever it needs a piece of memory, it will use these callbacks, using your memory manager that implements the functionality they need. The library can focus on what it does best: playing .swf files and you can take care of the platform specific details without having to make any changes to the library.

Let’s look at an example a bit closer to home: qsort. By now you should be able to understand the following function declaration:

void qsort( void *base
             , size_t num
             , size_t width
             , int (__cdecl *comp)
                      (const void* e1, const void* e2)
          );

You will find it in <stdlib.h> and it is a quicksort implementation that sorts the items in base for you, according to your specification. Now how do you specify it to order your items when it doesn’t know anything about the type of the elements? Simple: provide it with a callback function that tells qsort how to compare two elements with each other.

The base address of your list of items is given to qsort through the void *base parameter. It can then figure out how to iterate through the items in the list, because you tell it how many items it contains with num and how big each item is with width. Finally the callback function you provide tells qsort whether an item is smaller than, bigger than, or equal to the other item.

The following example (for Microsoft only, because of the use of _stricmp which is not part of the ANSI standard) reads and sorts the command line parameters using qsort and a callback function.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int comp(void const *arg1, void const *args) {
  // case insensitive comparison
  return _stricmp( *(char**)arg1, *(char**)arg2);
}

int main(int argc, char const *argv[])
{
  // remove application name from argv
  ++argv;
  --argc;
  // sort remaining arguments
  qsort((void*)argv, (size_t)argc, sizeof(char*), comp);
  // display result
  for (int idx=0; idx<argc; ++idx)
   (void)printf(“%s “, argv[idx]);
  (void)printf(“\n”);
}

Callback functions can also be very useful when you want to bind a token to a function. One of the examples I have shown you before in the previous article, contains a struct named RQRSTable. It contains a member named function and another one named header. Declared in a .cpp source file, structs like these allow you to configure your token/function binding centrally in the source code. They generally take on the following form:

static struct <StructName> {
  <member1 type> <member1 name>;
  ... 
  <memberN-1 type> <memberN-1 name>;
  <memberN type> <memberN name>;
} <array name>[] =
{ { <member value>, ..., <memberN-1 value>, <memberN value> }
, { <member value>, ..., <memberN-1 value>, <memberN value> }
...
};

Now that you have a static data object that can describe which function has to execute when a certain token is used. This can be very useful when you are parsing messages, upon which action has to be taken. If you don’t want to iterate to the array sequentially, you can always store the data in a hash table (like std::map) upon initialization and use the token as a key.

The function pointers in these structs are also callback functions. This is because, just like qsort, the function using them binds data to functions dynamically at runtime. This level of abstraction is very powerful because it allows you to create generic functions like qsort, platform independent libraries etc.

C++ has more tricks up its sleeve though. Allow me introduce you to functors.

Regular function pointers are quite easy to use, but as soon as you start using member function pointers, you need an object to use them on. They are no good to you otherwise.

You can also store both of them in a Functor and treat that functor object as a replacement function instead.

How does an object behave like a function? You overload operator () in a polymorphic MyFunctor base class from which we will implement derived functors. This way our main application can deal with MyFunctor without having to know what kind of specific derived implementations we have provided it. You can give it functors with extra debugging functionality or performance enhanced ones etc. The application won’t care; it will just call operator ().

// the abstract baseclass
class MyFunctor {
public:
  virtual ~MyFunctor() {}
  virtual int operator ()(char const *str)=0;
};

// derived implementation
template <class T> class DerFunctor : public MyFunctor {
public:
  DerFunctor(T* pObj, int (T::*funcPtr)(const char*))
     : m_funcPtr(funcPtr), m_pObject(pObj) {}

  int operator ()(char const *str) {
     return (m_pObject->*m_funcPtr)(str);
  }
private:
  int (T::*m_funcPtr)(const char*); // member func.ptr.
  T* m_pObject;                     // ptr. to object.
};

The constructor of DerFunctor takes a pointer to the object it can use the member function pointer on, which it receives as an argument as well. When we call operator () on an instantiated DerFunctor, it then executes that member function pointer on that object. Easy, isn’t it?

Here is how we can make good use of this.

class Dummy1 {
public:
  int Run(char const *str) { /*...*/ return 0; }
};

class Dummy2 {
public:
  int Run(char const *str) { /*...*/ return 1;
};

int main (int argc, char const *argv[]) {
  // here are the objects
  Dummy1 dummy1; 
  Dummy2 dummy2;
  // here are the functors
  DerFunctor<Dummy1> functor1(&dummy1, &Dummy1::Run);
  DerFunctor<Dummy2> functor2(&dummy2, &Dummy2::Run);
  // put them in an array to make it more interesting \
  MyFunctor* vtable[] = { &functor1, &functor2 };

  // make the call
  int res1 = functor1(“this is a test”);
  int res2 = (*vtable[1])(“this is a test”);
}

This functor example is extremely simplified and there is a lot more to be discussed. The base class I provided here for example, isn’t really generic and you won’t be able to reuse it really. Since these articles were about function pointers I will save the functors for another one.


"C++" 카테고리의 다른 글
  • Multithreading in C++ (0)2007/07/30
  • A Simple Garbage Collector for C++ (0)2007/07/30
  • Function Pointers (1)2007/07/30
  • DLL Conventions: Issues and Solutions (0)2007/07/27
  • More on Handling Basic Data Types (0)2007/07/27
2007/07/30 10:16 2007/07/30 10:16
Posted by webdizen
Tags C++Keyword C++, Function Pointer, 함수 포인터
No Trackback 1 Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3106

Leave your greetings.

  1. 임영택

    C++ 콜백함수에 대한 자료를 찾다가 여기까지 오게 되었네요. 좋은 자료 잘 보았구요.
    링크된 사이트에서 Part1/2/3 모두 잘 읽었습니다. SETI에 대해서 다시한번 더 알게 되었구요.
    모쪼록 성공하시길 빕니다.

    2008/01/21 01:55 [ Permalink : Modify/Delete : Reply ]
[로그인][오픈아이디란?]

«Prev  1  Next»

RSS HanRSS
Blog Image
webdizen
이 곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (2998)
Webdizen (134)
Life (6)
Diary (16)
Blog (9)
IDEA (1)
Travel (10)
Book (14)
Photo (7)
Movie (7)
Music (13)
Leisure Sports (10)
Funny (5)
Hardware (119)
Software (120)
Windows (5)
Unix & Linux (119)
Installation (4)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (805)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (3)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (3)
Network (66)
Web (78)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 시스템 제어
  • 삼육
  • 패키지
  • 메모리
  • 객체 비지향
  • 알고리즘
  • Interface
  • 패턴
  • 네트워크 포트
  • 능력
  • Debugging Trace Macro
  • Safari3
  • 퍼즐
  • GNU
  • 한서관
  • libpcap
  • Keyword
  • .NET Framework
  • NirSoft
  • 데이타 바인딩

Recent Articles

  • ASCII Code의 CRLF 제거 방법.
  • Hadoop 에서 c++ API 이용시....
  • Ubuntu Linux에서 Hadoop 구....
  • 내 심장을 한껏 뛰게한 "국가....
  • 스타 스키마 데이터베이스 설....

Recent Comments

  • ■ 온라인카지노 ▶ http://L....
    asdf 11/21
  • 그리고 혹시 해외여행자보험....
    kim 11/05
  • ★★실제 바다게임장과 똑같....
    asdf 11/04
  • sbsyama.co.to← 짱5000만당....
    asdf 11/04
  • ♡KicaZ??o(???) 바카라사....
    fdsf3fass 11/03

Recent Trackbacks

  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 02/11
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007
  • 마방진을 구하는 프로그램.
    Oranzie's BLOG 3 2007

Archive

  • 2009/09 (3)
  • 2009/08 (1)
  • 2009/03 (1)
  • 2009/02 (9)
  • 2009/01 (13)

Calendar

«   2009/11   »
일 월 화 수 목 금 토
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.