function object(functor) ...

As is known,in many advanced programming languages(esp. object oriented ones) like c/c++,c#,Java,etc., the function is only one of the programming syntax constructs,unlike that in some pure interpreted programming lanuage such as Javascript,SmallTalk and so on,which are also object oriented,the function itself is a first-class object,however,for example:
 
function Foo() { // note: Foo is an object
    this.sampleMemVar = 123;
    
this.sampleMemFun = function() {}; // create a new function object
    function() {}; // anonymouse function object
    var f = function(){}; // equal to function f() {} declaration,also create new function object
};

 
As a result,foo can behaves in the same way as regular object do,that is to say,foo can have properties,member functions,and can be extended,see below:
 

Foo.prototype.sampleVar 
= 0;
Foo.prototype.sampleFun 
= function(arglist) {}; // prototype is one of the properties of object Foo
Foo.sampleStaticVar = "sample static variable"// static variable
Foo.sampleStaticFun = function() // extend Foo with a static function
var foo = new Foo(); // applying new operator on a function object causing an instance of an Object is created with the members declared in the constructor,i.e.,Foo.
foo.toString(); // inherited from Object
typeof(foo); // you can call typeof operator on foo,where Object is returned
typeof(Foo); // call tpyeof operator on Foo,where Function is returned
printf(Foo.sampleStaticVar);
foo.sampleMemVar 
= 100// access instance variable
Foo.sampleStaticFun(); // call static method
foo.sampleMemFun(); // call instance method

 
No need to enumerate the examples any more. You can see that the function has no much differences from general objects,except that it does inherites from Function on the other hand.
 
Then how about the situation in c/c++,or others?
For example, we have a function,which can perform some action on two operands,and the specified action can only be determined at runtime.Then how to solve this problem?
 
Of course,you can use (memebr) function pointer like:
 
typedef int (*OpFunc)(int left,int right);


 
but you should first know the argument types and return type.
how about template?
 
template<class _Arg1,class _Arg2,class _Result>
_Result(
*OpFunc)(_Arg1 arg1,_Arg2 arg2); // this does not compile

 
You could never use template directly on typedef or object declarations.
Then maybe you want to encapsulate the concept in this way:
 
template<class _Arg1,class _Arg2,class _Result>
class Performer
{
public:
 typedef _Result (
*OpFunc)(_Arg1,_Arg2);
 Performer(OpFunc _opfunc) : m_opfunc(_opfunc)
 {
  _ASSERT(NULL 
!= _opfunc);
 }
 _Result Perform(_Arg1 arg1,_Arg2 arg2)
 {
  
return m_opfunc(arg1,arg2);
 }
private:
 OpFunc m_opfunc;
};

 
Yes,this works. However,function pointer itself is not an object oriented construct,as a result,lack of flexibility and extensibility.
 
Then,if you're familar with c#,you may want to use delegate.
And unlike template in c++,you can apply generic on delegate directly.
 

delegate _Result OpFunc<_Arg1,_Arg2,_Result>(_Arg1 arg1,_Arg2 arg2);
class Performer<_Arg1, _Arg2, _Result>
{
    
private OpFunc<_Arg1, _Arg2, _Result> opfun = null;
    
public Performer(OpFunc<_Arg1, _Arg2, _Result> _opfun)
    {
        
if (null == _opfun) throw new ArgumentException();
        
this.opfun = _opfun;
    }
    
public _Result Perform(_Arg1 arg1, _Arg2 arg2)
    {
        
return opfun(arg1, arg2);
    }
}

 
you can even implement you delegate in c++,only by making a wrapper to any function pointer.
No matter what you do with delegate,you are actually using function pointers,then again,lack of flexibility and extensibility.
 
So, why not use polymorphism?
If we can store the runtime action performer in an object,e.g.,action_performer,and we call the method on this object,where different object has different implementation for that action.
 

template
<class _Arg1,class _Arg2,class _Result>
class PerformerBase
{
public:
 
virtual _Result Perform(_Arg1 arg1,_Arg2 arg2) = 0;
};
template
<class _Arg1,class _Arg2,class _Result>
class AddPerformer : public PerformerBase<_Arg1,_Arg2,_Result>
{
public:
 _Result Perform(_Arg1 arg1,_Arg2 arg2)
 {
  
return arg1 + arg2;
 }
};
template
<class _Arg1,class _Arg2,class _Result>
class MinusPerformer : public PerformerBase<_Arg1,_Arg2,_Result>
{
public:
 _Result Perform(_Arg1 arg1,_Arg2 arg2)
 {
  
return arg1 - arg2;
 }
};

 
Yes,this also works and we can gain much flexibility and extensibility from this solution.
Then if we we can use function object as we do in Javascript,we can gain much more.
Forget operator overloading?( return to your c++ textbook for a look:-))
we can obtain a function object by encapsulate the function and overload it call operator,i.e.().
For example,
 
class Functor
{
public:
    
int operator()(int a,int b) { return a + b; }
};
Functor myFuncObj;
int x = myFuncObj(1,2);

 
Quite easy,right?
 
OK,then let's return to our problem,which is now trivial,given below:
 
template<class _Arg1,class _Arg2,class _Result>
class FunctorBase
{
public:
 
virtual _Result operator()(_Arg1 arg1,_Arg2 arg2) = 0;
};
template
<class _Arg1,class _Arg2,class _Result>
class AddFunctor : public FunctorBase<_Arg1,_Arg2,_Result>
{
public:
 _Result 
operator()(_Arg1 arg1,_Arg2 arg2)
 {
  
return arg1 + arg2;
 }
};
template
<class _Arg1,class _Arg2,class _Result>
class MinusFunctor : public FunctorBase<_Arg1,_Arg2,_Result>
{
public:
 _Result 
operator()(_Arg1 arg1,_Arg2 arg2)
 {
  
return arg1 - arg2;
 }
};
template
<class _Arg1,class _Arg2,class _Result>
class Performer
{
public:
 Performer(FunctorBase
<_Arg1,_Arg2,_Result> & functor)
  : m_functor(functor)
 {
 }
 _Result Perform(_Arg1 arg1,_Arg2 arg2)
 {
  
return m_functor(arg1,arg2);
 }
private:
 FunctorBase
<_Arg1,_Arg2,_Result> & m_functor;
};

 
In conclusion, you can implement your own specific function object(functor) even in c++,c#,etc.,then you can use function as general objects in your program with high flexibility,resuability and extensibility. Actually, if you look into the STL,you will find that many functions receive a functor as a parameter,e.g.,find_if in <algorithm> receives a predictor as a searching criteria. see declaration below:
 
template<class InputIterator, class Predicate>
   InputIterator find_if(
      InputIterator _First,
      InputIterator _Last,
      Predicate _Pred
   );

 
then you can call like this:
int arr[] = {1,2,3,4,5};
int * found = find_if(arr,arr + _countof(arr),greater<int>(2)); // find element that is greater thatn 2.
 

functors are declared in <functional> in STL.

posted @ 2007-09-15 08:03  dannyr|一个都不能少!  阅读(819)  评论(0编辑  收藏  举报