Function Pointer

Has two meanings. One meaning is a feature found in the C/C++ language, by which a pointer can be bound to a (non-member) function, which can be then invoked through the pointer. Function pointers are TypeSafe in that (ignoring casts to bypass the type system) the signature of the pointer must match the signature of the function(s) it is bound to.

The second meaning is a DesignPattern, part of the ObjectBasedProgramming pattern language. Discussion occurs on FunctionPointerDiscussion?. (This pattern is frequently used in languages like Java, which have no analog to C/C++ style function pointers).

Original at http://www.geocities.com/SiliconValley/Foothills/5962/functionpointer.htm


Intent

Provide a strategy to implement an polymorphic function, while allowing with ease the addition of subclasses that override the behaviour of the operation.

Motivation

The PolymorphicFunction pattern requires that a single function to implement a particular operation for all subclasses in the class family. This function would need to exhibit different behaviour for objects of different subclasses if the operation is overridden by the subclasses. A naive implementation of the polymorphic function would require modification every time a new subclass is added. This is not desirable as it increases the coupling between the subclasses. The resulting code would be less maintainable and readable.

Applicability

Applicability should be decided on an operation by operation basis. Some operations in a class family may benefit from this pattern while other would not. The Function Pointer pattern is applicable to an operation if:

Solution

Instead of hard-coding in the polymorphic function the behaviour for each subclass, a level of indirection is introduced through operation pointers. The operation pointer references the actual function supplying the required behaviour. The polymorphic function simply delegates its responsibility to the function referenced by the function pointer.

There are two principal variations:

  1. The function pointers are embedded in the instance data.

  2. The instance data does not contain the function pointers. The function pointers are stored in the class descriptor. By first identifying the class of the object and then looking up the class descriptor, the function pointer can be located.

Consequences

The Function Pointer pattern has three important consequences:

  1. Adding a subclass with overridden operations requires no changes to existing operations. The implementation of the subclasses are de-coupled. The addition of a new subclass does not require any change to any existing code and hence enhances maintainability.

  2. Increased memory usage (variation #1 only). The first variation can significantly increase memory consumption , as the instance data for two objects of the same subclass duplicates the function pointers. This however is not a consequence for variation #2.

  3. Increased architectural complexity (variation #2 only). The second variation demands the application of the ClassDescriptor pattern. If a class descriptor is not otherwise required, it will have to be created as a pre-requisite.

Sample Code

Consider the following class family:

[1]

The Object Handler superclass is the ancestor for many subclasses, three of which are shown above. The descendants of the Object Handler superclass typically override the three operations to provide the desired behaviour.

The polymorphic function ObjectHandlerFamilyAccessFn? implements the AccessFn? operation for the entire class family.

The following code segment shows an example implementation of ObjectHandlerFamilyAccessFn? with the FunctionPointer pattern variation #1 applied.

	int ObjectHandlerFamilyAccessFn?( void *pvInstanceData, param1, ... ) 
	{ 
		tsOBJECT_HANDLER *psObjectHandler; 
		int nResult; 

/* Cast the instance data to the underlying format */ psObjectHandler = (tsOBJECT_HANDLER*) pvInstanceData;

/* Call the actual function referenced by the function pointer */ nResult = (*(psObjectHandler->pfAccessFn))(param1, ... );

/* Return result */ return( nResult ); }

The following code segment shows an example implementation of ObjectHandlerFamilyAccessFn? with the FunctionPointer pattern variation #2 applied.

	int ObjectHandlerFamilyAccessFn?( void *pvInstanceData, param1, ... ) 
	{ 
		tsOBJECT_HANDLER *psObjectHandler; 
		tsOBJECT_HANDLER_CLASS_DESCRIPTOR sClassDescriptor; 
		int nResult; 

/* Cast the instance data to the underlying format */ psObjectHandler = (tsOBJECT_HANDLER*) pvInstanceData;

/* Get the class type */ nClassTag = psObjectHandler->nClassTag;

/* Look up the class dictionary to get the class descriptor */ /* Exact implementation depends on the design of the class dictionary */ sClassDescriptor = asObjectHandlerClassDict[nClassTag];

/* Look up the class descriptor to get the access fn */ pfAccessFn = sClassDescriptor.pfAccessFn;

/* Call the actual function referenced by the function pointer */ nResult = (*pfAccessFn)(param1, ... );

/* Return result */ return( nResult ); }

Known Uses

The Function Pointer pattern has been applied to the implementation of SNMP object handlers in Network Management Unit Software (NUS) developed by MAS Technology. The example above is an adaptation of the actual implementation.

Related Patterns

This pattern provides an implementation strategy to implement polymorphic functions described by the PolymorphicFunction pattern.

The PolymorphicFunctionWithEmbeddedBehaviour pattern describes an contrasting strategy to implement polymorphic functions.

Variation #2 of the FunctionPointer pattern requires the ClassTag and the ClassDescriptor pattern.

The ClassTag pattern is frequently applied to provide run-time object type identification. With the application of the FunctionPointer pattern variation #2, run-time object type identification may no longer be required, and with it the necessity of the ClassTag pattern.

EditText of this page (last edited May 12, 2005) or FindPage with title or text search