FUNCTIONS AND POINTERS
1. FUNCTIONS
A
function, which can also be referred to as subroutine, procedure, subprogram or
even method, carries out tasks defined by a sequence of statements called a
statement block that need only be written once and called by a program as many
times as needed to carry out the same task.
Functions
may depend on variables passed to them, called arguments, and may pass results of
a task on to the caller of the function, this is called the return value.
It is
important to note that a function that exists in the global scope can also be
called global function and a function that is defined inside a class is called
a member function. (The term method is commonly used in other programming
languages to refer to things like member functions, but this can lead to
confusion in dealing with C++ which supports both virtual and non-virtual
dispatch of member functions.)
2. Declarations
A
function must be declared before being used, with a name to identify it, what
type of value the function returns and the types of any arguments that are to
be passed to it. Parameters must be named and declare what type of value it
takes. Parameters should always be passed as const if their arguments are not
modified. Usually functions performs actions, so the name should make clear
what it does. By using verbs in function names and following other naming
conventions programs can be read more naturally.
The next
example we define a function named main that returns an integer value int and
takes no parameters. The content of the function is called the body of the
function. The word int is a keyword. C++ keywords are reserved words, i.e.,
cannot be used for any purpose other than what they are meant for. On the other
hand main is not a keyword and you can use it in many places where a keyword
cannot be used (though that is not recommended, as confusion could result).
int
main()
{
// code
return 0;
}
The
inline keyword declares an inline function, the declaration is a (non-binding)
request to the compiler that a particular function be subjected to in-line
expansion; that is, it suggests that the compiler insert the
complete body of the function in every context where that function is used and
so it is used to avoid the overhead implied by making a CPU jump from one place
in code to another and back again to execute a subroutine, as is done in naive
implementations of subroutines.
inline
swap( int& a, int& b) { int const tmp(b); b=a; a=tmp; }
When a
function definition is included in a class/struct definition, it will be an
implicit inline, the compiler will try to automatically inline that function.
No inline keyword is necessary in this case; it is legal, but redundant, to add
the inline keyword in that context, and good style is to omit it.
Example:
struct length
{
explicit
length(int metres) : m_metres(metres) {}
operator
int&() { return m_metres; }
private:
int
m_metres; };
Inlining
can be an optimization, or a pessimization. It can increase code size (by
duplicating the code for a function at multiple call sites) or can decrease it
(if the code for the function, after optimization, is less than the size of the
code needed to call a non-inlined function). It can increase speed (by allowing
for more optimization and by avoiding jumps) or can decrease speed (by
increasing code size and hence cache misses).
One
important side-effect of inlining is that more code is then accessible to the
optimizer. Marking a function as inline also has an effect on linking: multiple
definitions of an inline function are permitted (so long as each is in a
different translation unit) so long as they are
identical.
This allows inline function definitions to appear in header files; defining
non-inlined functions in header files is almost always an error (though
function templates can also be defined in header files, and often are).
Mainstream
C++ compilers like Microsoft Visual C++ and GCC support an option that lets the
compilers automatically inline any suitable function, even those that are not
marked as inline functions. A compiler is often in a better position than a
human to decide whether a particular function should be inlined; in particular,
the compiler may not be willing or able to inline many functions that the human
asks it to.
Excessive
use of inlined functions can greatly increase coupling/dependencies and
compilation time, as well as making header files less useful as documentation
of interfaces.
Normally
when calling a function, a program will evaluate and store the arguments, and
then call (or branch to) the function's code, and then the function will later
return back to the caller. While function calls are fast (typically taking much
less than a microsecond on modern processors), the overhead can sometimes be
significant, particularly if the function is simple and is called many times.
One
approach which can be a performance optimization in some situations is to use
so-called inline functions. Marking a function as inline is a request
(sometimes called a hint) to the compiler to consider replacing a call to the
function by a copy of the code of that function.
The
result is in some ways similar to the use of the #define macro, but as
mentioned before, macros can lead to problems since they are not evaluated by
the preprocessor. inline functions do not suffer from the same problems.
If the
inlined function is large, this replacement process (known for obvious reasons
as "inlining") can lead to "code bloat", leading to bigger
(and hence usually slower) code. However, for small functions it can even
reduce code size, particularly once a compiler's optimizer runs.
Note that
the inlining process requires that the function's definition (including the
code) must be available to the compiler. In particular, inline headers that are
used from more than one source file must be completely defined within a header
file (whereas with regular functions that would be an error).
The most
common way to designate that a function is inline is by the use of the inline
keyword. One must keep in mind that compilers can be configured to ignore the
keyword and use their own optimizations.
Further considerations
are given when dealing with inline member function, this will be covered on the
Object-Oriented Programming
3. Parameters and arguments
The
function declaration defines its parameters. A parameter is a variable which
takes on the meaning of a corresponding argument passed in a call to a
function.
An
argument represents the value you supply to a function parameter when you call
it. The calling code supplies the arguments when it calls the function.
The part
of the function declaration that declares the expected parameters is called the
parameter list and the part of function call that specifies the arguments is
called the argument list. //Global functions declaration
int subtraction_function( int parameter1, int
parameter2 ) { return ( parameter1 - parameter2 ); } //Call to the above
function using 2 extra variables so the relation becomes more evident
int
argument1 = 4; int argument2 = 3;
int
result = subtraction_function( argument1, argument2 ); // will have the same
result as
int result
= subtraction_function( 4, 3 );
Many
programmers use parameter and argument interchangeably, depending on context to
distinguish the meaning. In practice, distinguishing between the two terms is
usually unnecessary in order to use them correctly or communicate their use to
other programmers. Alternatively, the equivalent terms formal parameter and
actual parameter may be used instead of parameter and argument.
4. Parameters
We can
define a function with no parameters, one parameter, or more than one, but to
use a call to that function with arguments you must take into consideration
what is defined. Empty parameter list
//Global
functions with no parameters
void
function() { /*...*/ }
//empty
parameter declaration equivalent the use of void
void
function( void ) { /*...*/ }
Multiple
parameters
The
syntax for declaring and invoking functions with multiple parameters can be a
source of errors. When you write the function definition, you must declare the
type of each and every parameter.
// Example
- function using two int parameters by value
void
printTime (int hour, int minute) {
std::cout
<< hour;
std::cout
<< ":";
std::cout
<< minute;
}
It might
be tempting to write (int hour, minute), but that format is only legal for
variable declarations, not for parameter declarations.
However,
you do not have to declare the types of arguments when you call a function.
(Indeed, it is an error to attempt to do so).
Example
int main
( void ) {
int hour
= 11;
int
minute = 59;
printTime(
int hour, int minute ); // WRONG!
printTime(
hour, minute ); // Right!
}
In this
case, the compiler can tell the type of hour and minute by looking at their
declarations. It is unnecessary and illegal to include the type when you pass
them as arguments..
5. by pointer
A
function may use pass by pointer when the object pointed to might not exist,
that is, when you are giving either the address of a real object or NULL.
Passing a pointer is not different to passing anything else. Its a parameter
the same as any other. The characteristics of the pointer type is what makes it
a worth distinguishing.
The
passing of a pointer to a function is very similar to passing it as a
reference. It is used to avoid the overhead of copying, and the slicing problem
(since child classes have a bigger memory footprint that the parent) that can
occur when passing base class objects by value. This is also the preferred
method in C (for historical reasons), were passing by pointer signifies that
wanted to modify the original variable. In C++ it is preferred to use
references to pointers and guarantee that the function before dereferencing it,
verifies the pointer for validity.
#include <iostream>
void MyFunc( int *x )
{
std::cout
<< *x << std::endl; // See next section for explanation
}
int
main()
{
int i;
MyFunc( &i );
return 0;
}
Since a
reference is just an alias, it has exactly the same address as what it refers
to, as in the following example:
#include
<iostream>
void
ComparePointers (int * a, int * b)
{
if (a ==
b)
std::cout<<"Pointers are the
same!"<<std::endl; else
std::cout<<"Pointers
are different!"<<std::endl;
}
int
main()
{
int i, j;
int& r = i;
ComparePointers(&i, &i);
ComparePointers(&i, &j); ComparePointers(&i, &r);
ComparePointers(&j, &r);
return 0;
}
In
object-oriented programming, a friend function that is a "friend" of
a given class is allowed access to private and protected data in that class
that it would not normally be able to as if the data was public. Normally, a
function that is defined outside of a class cannot access such information.
Declaring a function a friend of a class allows this, in languages where the
concept is supported.
A friend
function is declared by the class that is granting access, explicitly stating
what function from a class is allowed access. A similar concept is that of
friend class.
Friends
should be used with caution. Too many functions or external classes declared as
friends of a class with protected or private data may lessen the value of
encapsulation of separate classes in object-oriented programming and may
indicate a problem in the overall architecture design. Generally though, friend
functions are a good thing for encapsulation, as you can keep data of a class
private from all except those who you explicitly state need it, but this does
mean your classes will become tightly coupled.
6. Use cases
This
approach may be used in friendly function when a function needs to access
private data in objects from two different classes. This may be accomplished in
two similar ways a function of global or namespace scope may be declared as
friend of both classes a member
function of one class may be declared as friend of another one.
#include
<iostream>
using
namespace std;
class
Foo; // Forward declaration of class Foo in order for example to compile. class
Bar {
private:
int a; public:
Bar():
a(0) {}
void
show(Bar& x, Foo& y);
friend
void show(Bar& x, Foo& y); // declaration of global friend
};
class Foo
{ private: int b; public:
Foo():
b(6) {}
friend
void show(Bar& x, Foo& y); // declaration of global friend
friend
void Bar::show(Bar& x, Foo& y); // declaration of friend from other
class
};
// Definition
of a member function of Bar; this member is a friend of Foo void
Bar::show(Bar& x, Foo& y) {
cout
<< "Show via function member of Bar" << endl; cout
<< "Bar::a = " << x.a << endl;
cout
<< "Foo::b = " << y.b << endl;
}
// Friend
for Bar and Foo, definition of global function
void
show(Bar& x, Foo& y) {
cout
<< "Show via global function" << endl; cout <<
"Bar::a = " << x.a << endl;
cout
<< "Foo::b = " << y.b << endl;
}
int main() { Bar a; Foo b;
show(a,b);
a.show(a,b);
}
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.