Tuesday, 25 June 2013

Functions - III

Inline Functions

The main objective of using functions in a program is to save memory space, which becomes appreciable when a function is likely to be called many times. However, every time a function is called it takes a lot of extra time in executing a series of instructions for tasks such as jumping to the function, saving registers, pushing arguments into the stack and return to the calling function. when a function is small, a substantial percentage of execution time maybe spent in such overheads.

One solution to this problem is to use a macro definition, as you would be aware it to be macros from C. Pre-processor macros are used in C. The major drawback with macros is that they are not really functions and hence any error would go unchecked as error checking is not done during compilation. 

C++ has a feature which presents the perfect solution to his problem. To eliminate the cost of calls to small function C++ has a new feature called the Inline Function. An inline function is a function that is expanded in line when it is invoked. That is, the compiler replaces the function call with the corresponding function code (Which you might consider similar to macro expansion). The inline functions are defined as follows :-

inline function-header
{
         function body
}

Example

inline double cube (double a)
{
     return (a*a*a);
}

The above inline function can be invoked by statements like 

c = cube (3.0);

d = cube (2.5+1.5);

On the execution of these statements, the values of c and d will be 27 and 64 respectively. If the arguments are expressions like 2.5+1.5, the function passes the value of the expression , 4 in this case. This makes the inline feature far superior to macros.

It is easy to make a function inline. All we need is to do is to prefix a keyword inline to the function definition. All the functions must be defined before they are called.

*NOTE
We should be extremely careful before making a function inline. The speed benefits of inline functions diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function, and the benefits of inline functions will be lost. In such cases, the use of normal functions will be more meaningful. Usually, functions are made inline when they are small enough to be defined in one or two lines.

Limitations

The inline keyword merely sends a request and not a command to the compiler. The compiler may ignore the request if the function definition is too long or too complicated and might compile the function as a normal function.

Some of the limitations where inline functions do not work :-

  • For functions returning values, if a loop, a switch, or a goto statement exists.
  • For functions not returning values, if a return statement exists.
  • If function contains a static variable.
  • If inline functions are recursive.
A program to illustrate the use of inline function

#include<iostream>

using namespace std;

inline float mul (float x, float y)
{
     return (x*y);
}

inline double div (double p, double q)
{
      return (p/q);
}

int main()
{
       float a = 12.965;
       float b = 9.810;

       cout<<mul (a,b)<<"\n";
       cout<<div (a,b)<<"\n";
     
       return 0;
}


The output of the program is 
127.187
1.32161

Default Argument

C++ gives the provision to call a function without specifying all its arguments. In such cases, the function assigns a default value to the parameter which does not have a matching argument in the function call. Default values are specified when the function is declared. The compiler looks at the prototype to see how many arguments a function uses and alerts the program for possible default values. 

Here is an example of a prototype of a function declaration with default values :-

float amount (float principal, int period, float rate =0.15);

The default value is specified in a manner syntactically similar to a variable initialization. The above prototype declared a default value of 0.15 to the argument rate. A subsequent function call like

value = amount (5000, 7);        //Argument for rate is missing

passes the value of 5000 to the principal and 7 to the period and then lets the function use default value of 0.15 for rate.

The call

value = amount (5000, 5, 0.12)  //No argument missing

passes an explicit value of 0.12 to rate.

A default argument is checked for type at the time of declaration and evaluated at the time of call. One important point to note is that only the trailing arguments can have default values and therefore we must add defaults from right to left. We cannot provide a default value to a particular argument in the middle of an argument list. 

Note :- Default arguments are useful in situations where some arguments always have the same value. For instance, bank interest may remain same for all the customers taking a particular type of loan for a particular period. It also provides a greater flexibility to the programmers. A function can be written with more parameters than are required for its most common application. Using default arguments, a programmer can use only those arguments that are meaningful to a particular situation.

Advantages of Default Arguments :-

  • We can use default arguments to add new parameters to the existing functions.
  • Default arguments can be used to combine similar functions into one.

Constant Argument

In C++, an argument to a function can be declared as const  as shown below :-

int strlen ( const char *p);
int length (const string &s);

The qualifier const tells the compiler that the function should not modify the argument. The compiler will generate an error when this condition is violated. This type of declaration is significant only when we pass arguments by reference or pointers.

Function Overloading

As we know overloading means the use of the same thing for different purposes. C++ also permits overloading of functions.This means that we can use the same function name to create functions that perform a variety of different tasks. This is known as function polymorphism in OOP concept.

Using the concept of function overloading we can design a family of functions with one function name but with different argument lists. The function would perform different operations depending on the argument list in the function call. The correct function to be invoked is determined by checking the number and type of the arguments but not on the function type. For example, an overloading add() function handles different types of data as shown below :-

//declarations

int add (int a, int b)                                    //prototype 1
int add (int a, int b, int c)                            //prototype 2
double add (double a, double b)                   //prototype 3
double add (double p, int q)                        //prototype 4
double add (int x, double y)                        //prototype 5

//Function calls

cout<<add (5,10);                       //uses prototype 1
cout<<add (5,10.50,8);                //uses prototype 2
cout<<add (12.5,10.9);                //uses prototype 3
cout<<add (5.78,10);                   //uses prototype 4
cout<<add (5,10.98);                   //uses prototype 5

A function call first matches the prototype having the same number and type of arguments and then calls the appropriate function for execution. A best match must  be unique. The function selection involves the following steps.
  • The compiler firsts tries to find an exact match in which the types of actual arguments are the same and uses that function.
  • If an exact match is not found, the compiler uses the integral promotions to the actual arguments, such as,  
       char to int
       float to double
      to find a match
  • When either of the  fails, the compiler tries to use the built n conversions to the actual arguments and then uses the function whose match is unique. If the conversion is possible to have multiple matches then the compiler will generate an error message. Suppose we use the following two functions 
       long square (long n)
       double square (double x)

       A function call such as square (10)
     
       will cause an error because int argument can be converted to either long        
       or double thereby creating an ambiguous situation as to which version of 
       square() should be used.
  • If all of the steps fail, then the compiler will try the user-defined conversions in the combination with integral promotions and built in conversions to fund a unique match. User defined conversions are often used in handling class objects. 
Note :- Overloading of functions should be done with caution. We should not overload unrelated functions and should reserve function overloading for functions that perform closely related tasks. Sometimes, the default arguments may be used instead of overloading. This may reduce the number of functions to be defined.

Thats all of functions that we need to know as of now.

Tasks :-

Q. Write a C++ program that will illustrate Default argument and function overloading features.