BINDING IN C++
Binding refers to the process that is used to convert identifiers
(such as variable and function names) into machine language addresses. Although
binding is used for both variables and functions, in this lesson we’re going to
focus on function binding.
Early binding
Most of the function calls the compiler
encounters will be direct function calls. A direct function call is a statement
that directly calls a function. For example:
#include
<iostream>
void
PrintValue(int nValue)
{
std::cout
<< nValue;
}
int
main()
{
PrintValue(5);
// This is a direct function call
return
0;
}
|
Direct function calls can be resolved using a
process known as early binding. Early binding (also called
static binding) means the compiler is able to directly associate the identifier
name (such as a function or variable name) with a machine address. Remember
that all functions have a unique machine address. So when the compiler
encounters a function call, it replaces the function call with a machine
language instruction that tells the CPU to jump to the address of the function.
Let’s take a look at a simple calculator program
that uses early binding:
#include
<iostream>
using
namespace std;
int
Add(int nX, int nY)
{
return
nX + nY;
}
int
Subtract(int nX, int nY)
{
return
nX - nY;
}
int
Multiply(int nX, int nY)
{
return
nX * nY;
}
int
main()
{
int
nX;
cout
<< "Enter a number: ";
cin
>> nX;
int
nY;
cout
<< "Enter another number: ";
cin
>> nY;
int
nOperation;
do
{
cout
<< "Enter an operation (0=add, 1=subtract, 2=multiply): ";
cin
>> nOperation;
}
while (nOperation < 0 || nOperation > 2);
int
nResult = 0;
switch
(nOperation)
{
case
0: nResult = Add(nX, nY); break;
case
1: nResult = Subtract(nX, nY); break;
case
2: nResult = Multiply(nX, nY); break;
}
cout
<< "The answer is: " << nResult << endl;
return
0;
}
|
Because Add(), Subtract(), and Multiply() are
all direct function calls, the compiler will use early binding to resolve the
Add(), Subtract(), and Multiply() function calls. The compiler will replace the
Add() function call with an instruction that tells the CPU to jump to the
address of the Add() function. The same holds true for for Subtract() and
Multiply().
Late Binding
In some programs, it is not possible to know
which function will be called until runtime (when the program is run). This is
known as late binding (or dynamic binding). In C++, one way to get
late binding is to use function pointers. To review function pointers briefly,
a function pointer is a type of pointer that points to a function instead of a
variable. The function that a function pointer points to can be called by using
the function call operator (()) on the pointer.
For example, the following code calls the Add()
function:
int
Add(int nX, int nY)
{
return
nX + nY;
}
int
main()
{
//
Create a function pointer and make it point to the Add function
int
(*pFcn)(int, int) = Add;
cout
<< pFcn(5, 3) << endl; // add 5 + 3
return
0;
}
|
Calling a function via a function pointer is
also known as an indirect function call. The following calculator program is
functionally identical to the calculator example above, except it uses a
function pointer instead of a direct function call:
#include
<iostream>
using
namespace std;
int
Add(int nX, int nY)
{
return
nX + nY;
}
int
Subtract(int nX, int nY)
{
return
nX - nY;
}
int
Multiply(int nX, int nY)
{
return
nX * nY;
}
int
main()
{
int
nX;
cout
<< "Enter a number: ";
cin
>> nX;
int
nY;
cout
<< "Enter another number: ";
cin
>> nY;
int
nOperation;
do
{
cout
<< "Enter an operation (0=add, 1=subtract, 2=multiply): ";
cin
>> nOperation;
}
while (nOperation < 0 || nOperation > 2);
//
Create a function pointer named pFcn (yes, the syntax is ugly)
int
(*pFcn)(int, int);
//
Set pFcn to point to the function the user chose
switch
(nOperation)
{
case
0: pFcn = Add; break;
case
1: pFcn = Subtract; break;
case
2: pFcn = Multiply; break;
}
//
Call the function that pFcn is pointing to with nX and nY as parameters
cout
<< "The answer is: " << pFcn(nX, nY) << endl;
return
0;
}
|
In this example, instead of calling the Add(),
Subtract(), or Multiply() function directly, we’ve instead set pFcn to point at
the function we wish to call. Then we call the function through the pointer.
The compiler is unable to use early binding to resolve the function
call pFcn(nX, nY) because it cannot tell which function pFcn will be
pointing to at compile time!
Late binding is slightly less efficient since it
involves an extra level of indirection. With early binding, the compiler can
tell the CPU to jump directly to the function’s address. With late binding, the
program has to read the address held in the pointer and then jump to that
address. This involves one extra step, making it slightly slower. However, the
advantage of late binding is that it is more flexible than early binding,
because decisions about what function to call do not need to be made until run
time.
Comments
Post a Comment