Wednesday 30 March 2016

All about functions in C++

Functions and mostly functions are enough to code the solution for any problem and that too very efficiently. I have the entire legacy of C language to back me up on this.
Starting off with a quick definition, functions are nothing but a name or a signature for a piece of code that can be used as many times as one likes by using the name/ signature and also passing some additional information (arguments) if need be.

A function must be declared, defined and used. Except the last bit (used) is optional.
Here is the general form of a function declaration and definition:
return type name(parameter list)
{
      body of the function.
}
I assume the reader is familiar with such basics of functions. Remember this article is intended for refreshing some very vital and some what in depth concepts about functions in C++. It does not actually contain everything there is to know about functions in C/C++. But I'll tell you this, if you stay with me throughout this article, you are assured a superior knowledge of functions then most students out there. Also the facts/ reasons are in no particular order:

A function can return any type of data except for an array. I guess that is a perfectly fine way of saying what I wanted to say. 

The parameter list, the one I mentioned in the general form of the function bit, is nothing but a comma separated list of the form: 
type name1, type name2, ......

As you might have noticed, the parameter looks a lot like a bunch of variable declarations (with strict and subtle differences of course). In fact you can sure think that way. It is a nice little analogy to draw in your mind when thinking about parameters and arguments. The analogy goes something like this:
The function defines variable inside its parameter list which catch the value of the arguments passed to it. These parameters are called Formal Parameters.
If the parameter is supposed to be empty then let it be empty. There is no need to write the keyword void  inside the parenthesis of the function declaration indicating the absence of any parameters for the function. In C++:
int func() and int func(void) are the same.

You can define a function in many places inside a program. Example, in a class, in a structure, etc. What you can't do is nest a function definition inside of another function definition. This is to say that you cannot define a function within a function.


Call by value and Call by reference:
Passing an argument to a function can be done in two principle ways. In call by value, the values of the variable passed as arguments to the function at the time of calling the function are copied and are pasted as the values of the formal parameters of the function. Hence the function is only able to affect the values of its formal parameters and the original variable passed as arguments are not affected. Basically, a copy of the variable is given as argument to work with, the original variable remains untouched and hence unaltered.
int twice(int a)
{
  return 2*a;
}
int main()
{
  int x=10;
twice(x);//This line baicially means a=x where a is the local                               variable inside the function twice.
}
In call by reference the function to be called does not expect actual values as its argument. It anticipated the addresses that holds the actual data. The function then goes on and makes changes at the address specified hence changing the actual variable's values.
int twice(int "A SPECIAL VARIABLE THAT CAN HOLD THE ADDRESS OF THE TYPE SPECIFIED" aka a) 
{
return 2*(*a); /*return the twice of the value at address stored at a.*/
}
int main()
{
int x=10;
twice(&x); /*here the address of x is passed as an address is expected by the function.*/
}

Now a (the special variable) has to be something that can hold an address :
1) a can be a pointer (as in C) twice(int *a);
2) a can be something that will explained later.


Returning from a function:
One can return from a function with or without a return value. Both of this can be done using either the return statement or by simply reaching the end of the function i.e. '}'.
In C++, if a function is specified as returning a value, any return statement within it must have a value associated with it. However, if execution reaches the end of a non-void function, then a garbage value is returned. Although this condition is not a syntax error, it is still a fundamental flaw and should be avoided.
If a function returns a value, it is not necessary to assign it to some variable. Because if a value returning function is called without using it in an expression or assignment, all of its functionality is executed and the return statement is ignored. So :
int prnt()
{
  cout<<"hey";
return 11;
}
int x=prnt() 
will assing 11 to x but after it has printed "hey" on the screen.

On the other hand, the following statement:
prnt(); 
will just print "hey" and return nothing to nobody.

Interestingly, 
cout<<prnt();
will print the following on the screen : "hey11".

Returning Pointers:
As I said a function can return anything, anything but an array. And as with most things, pointers have a way of being at the center of the action of this one as well. We can very well have a function whose return type is like that of a pointer. This of course means that the function will be returning an address. 
type * name(..)
{
....
return "Some Address";
}


Function Prototypes:
A function prototype is nothing but a function declaration without the body of the function i.e. the code inside of the curly braces and without the curly braces themselves. It looks like this:
int abc(...); 
Function prototype must occur before we call the function. And of course the definition of the function can follow even after function has been called and used.
Any standard library function used by your program must be prototyped. To accomplish this, you must include the appropriate header for each library function. All necessary headers are provided by the C/C++ compiler. In C, the library headers are (usually) files that use the .H extension. In C++, headers may be either separate files or built into the compiler itself. In either case, a header contains two main elements: 
1) Any definitions used by the library functions and 
2) The prototypes for the library functions.
Functions with variable length parameter list:
We are all taught this one fundamental rule, if the function has n number of parameters, we must pass it n number of arguments. Nothing less than n is acceptable (unless the concept of default parameters is used) and surely any number of arguments more than n will simple just make the compiler fire at you with abusive and hurtful error messages. 
Well as it turns out, we have a way of getting around the later part of the two prohibited situations described above. This means we can if we want to, define a function in such a way that it will work properly even if more arguments are passed to it then expected/ needed. A function that can have a variable number of arguments passed to it takes the following form:
int func(int a,int b, ...)
The the three dots are necessary syntax.
The above function must be called with at least two int arguments and after that it can have any number of (zero or more) arguments passed to it. The extra arguments are ignored completely by the compiler.
Any function that uses a variable number of parameters must have at least one actual parameter. For example, this is incorrect:
int func(...); /* illegal */
The point of this is that all other parameters are nameless and hence are unusable, so they will basically be ignored, its just to make sure that the function works correctly despite of any number of arguments we end up giving it.
Inline Functions:
In C++, you can create short functions that are not actually called; rather, their code is expanded in line at the point of each invocation. This process is similar to using a function-like macro. To cause a function to be expanded in line rather than called, precede its definition with the inline keyword.
inline int fn()
{
return 2;
}
int main()
{
return fn();
}
Like register (read about it in the keywords article), inline is a request not a command, the compiler can ignore this and can call the function as a normal functions. This happens when we make a recursive function into an inline function. The compiler does not make it inline it just ignores this request and uses this function as a normal one.

The use of ::
Sometimes we can run into situations where a function has a local variable with exactly the same name as that of a global variable (or variable of higher scope). In these cases, we can use the :: operator to differentiate a global variable from a local one. 
int i; // global i
void f()
{
int i; // local i
::i = 10; // now refers to global i
.
.
.
}
Function Overloading:
Function overloading is the process of having the same name for two (or more) different functions. The name of the two (or more) functions is same but the difference lies in the function body and the argument list. The return type of two overloaded functions can be different but that alone is not enough to differentiate two functions with the same name. Either the type or the number or both things or the parameters to the functions should be different.
The most important use of function overloading is overloading constructors:
Overloading a constructor is really easy, just have constructors with different parameters in them. Different here can be qualified by a different number of parameters and/or different type of at least one parameter.
Default Arguments:
What do we mean by a default value? It's a value provided in case nothing else is available. In the default arguments, a parameter of a function is given a default value. This default value can be over written if an argument is passed corresponding to the parameter. If no such argument is passed then this default value is considered.
int haha(int x=2) //2 is the default value
{}
haha(); // in this case 2 would be used.
haha(3); //in this case 2 would be used.

All the parameters with default values must be to the right of all the parameters with no default values.
int haha(int x, int y=2, int z) // this is wrong:
int haha(int x, int z, int y=2) /*this is correct, no default value less parameter should be to the right of a default valued parameter*/
This concept can be used as an alternative to overloading parameter-less constructors in a class.

No comments:

Post a Comment