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.