So far, we have learned how to declare and define simple
functions. Imagine you want to write a program that calculates an item’s
purchase price based on the item’s store price added the tax. The tax rate is
a percentage value. This means a tax rate set at 7.50% in C++ terms is equal to
0.075 (because 7.50/100 = 0.075). The tax amount collected on a purchase is
taken from an item’s price; its formula is:

We also learned to use files to group functions that share
an assignment. Furthermore, to reduce the likelihood of name conflicts, we
learned to create our entities in namespaces. An important aspect we need to
study are the functions needs, that is, the external things a function would
need in order to carry its assignment.

Practical Learning: Using Functions

Create a new project using the Console Wizard. To save the project, on the
Standard toolbar, click the Save All button.

Create a new folder called GCS4 and
display it in the Save In combo box. Save the unit as Main.cpp
and save the project as CleaningOrders

To create a new unit, on the Standard toolbar, click the New button
and, in the New property page of the New Items dialog box, scroll down and
double-click Unit.

Some functions will need to receive a value in order
to perform their assignment; some others will not. Some function will
have many needs and some others will not. A function’s need is called
a parameter. If a function has a lot of such needs, these are its
parameters. A parameter is the type of the variable that the function
would need to perform its assignment. The most important aspect of a
parameter is its data type. This data type is required when the function
is declared. When the function is defined, you must specify both the
data type and the name of the parameter.

When declaring a function that use one or more parameters,
specify each parameter with a data type and an optional name. Here are examples
of declaring functions that take parameters:

The type of value that a function needs is called a
parameter. The actual value that would be processed by the function is called an
argument. Supplying the value to a function is referred to as passing the
argument. When a function is declared, the argument must be specified by its
data type. When the function is called, the argument can be passed using the
name of a variable of the same type. You can also pass an actual value to the
function instead of a variable name.

To use the result of one function inside of another
function, that is, to call a function from another function, specify the name of
the function and its list of arguments (if any) inside of parentheses; only the
name of each argument is needed. Suppose you define the following functions:

When declaring a function, the compiler does not require
that you supply a name for each argument, it only needs to know the type of
argument(s) and the number of arguments a function takes. This information is
completely provided by the presence of a data type. This means you can declare
your functions as follows:

When defining functions that have been declared as done
above, you must provide a name for each argument that you intend to use.

The compiler also does not care about the name you give an
argument when declaring a function. When implementing the function, you just
have to remember to use the same name(s) included in the parentheses of the
function. Here are examples of functions that take arguments:Here are examples:

As seen already, the return keyword is used to return
an appropriate value from a non-void function. In fact, the item on the right
side of the return keyword could be a simple value or a complete
expression. Fortunately, the compiler is able to evaluate this item and find out
whether it is conform to the return type on the left side of the function name.
For this reason, inside of the function that performs a calculation and returns
its result, you do not have to first declare a variable that would hold the
return value; as long as you provide an appropriate value or expression on the
right side of the return keyword, the compiler would be satisfied.
Therefore, the above functions could have been implemented as follows:

When you call a function B() from function A(), function A()
sends a request and must get to Function B(). This is sometimes cumbersome for a
long function that is calling a small or short function. Whenever your program
includes a small function, C++ allows you to include such a function where it is
being called. When function B() calls function A(), instead of sending a request
to function A(), the compiler would include a copy of function A() into function
B() where it is being called. Such a function (function A()) is qualified
inline.

To declare a function as inline, use the inline keyword on the
left side of the function. Here is an example:

inline double CalculateDiscount(double, double);

When defining the function, use the inline keyword in the
same way. Here is an example that makes use of an inline function:

The Starter() function receives one argument passed when it
is called. The called function also receives the same argument every time.
Looking at the result, the argument passed to the function and the local
variables declared inside of the called function keep the same value every time
the function is called. That is, when the Starter() function is exited, the
values remain the same.

We know that, when a function is defined, any variable
declared locally belongs to the function and its influence cannot expand beyond
the presence of the function. If you want a locally declared variable to keep
its changed value when its host function is exited, you can declare such a
variable as static.

To declare a static variable, type the keyword static
on the left of the variable’s data type. For example, if you plan to declare a
Radius variable as static in an Area() function, you could write:

Notice that, this time, each local variable keeps its newly
changed value when the function exits. Since a function’s argument can receive
different values as the function is called different times, we can test our
program by passing different values to its argument as follows:

All the variables that we have used so far were declared in,
and passed to, the random memory (RAM). Once a variable is declared and
“put” in the memory, whenever it is involved in a calculation or assignment,
the microprocessor sends a request to the memory to retrieve the value of the
variable.

The Central Processing Unit (CPU), also called the
microprocessor, has its own memory. The microprocessor is made of memory cells
called registers. Unlike the memory in the RAM, the access of the memory in the
microprocessor is more precise; so precise that the registers are referred to by
using their names. Some of the most commonly used registers (also called general
purpose registers) are called EAX, EBX, ECX, EDX, ESI, etc. These registers are
mostly used in the Assembly Language for low-level programming. Using registers
allows the programmer to write assignments directly destined for the
microprocessor. The assignments and operations in the Assembly language are
called instructions. When instructions are used by registers, the processing of
the program is fast because the microprocessor does not have to retrieve the
values of the variables in the RAM; these values, since existing in the
registers, are readily available.

Borland C++ Builder (and most popular compilers) allow you
to include Assembly Language code in your program. Using this feature, you can
write a section or sections of Assembly language. A section that has Assembly
code starts with __asm followed by some other techniques. When the compiler
encounters this keyword, it knows that the subsequent code would be in Assembly
language and it would treat it accordingly. For example, instead of performing a
calculation in the RAM, the following program will assign values to two integer
variables, namely Number1 and Number2, then it calculate their sum of those two
numbers and stores the result in another variable called Result. After the
calculation, the Assembly section sends the result back to the C++ compiler to
display the variables and their values:

C++ Builder ships with a version of Assembly language so
that if you are interested in adding low-level code, you do not have to purchase
an assembler. In fact, C++ installs TASM (known as Turbo Assembler), the award
wining Assembler from Borland. This means that, if you want to learn Assembly,
you may not have to purchase it anymore (unfortunately, it is not documented).
Alternatively, the C++ Builder compiler has its own Assembler known as Inline
Assembly. This allows you to embed Assembly code in your programs.

The ability for C++ Builder to recognize Assembly code
allows you to pass arguments to registers. For example, you can pass arguments
to the EAX, EBX, ECX, or EDX, etc registers to speed the compilation process.
Fortunately, you do not need to learn Assembly language (although you are
encouraged to do so) to speed your code in C++ Builder. As an alternative, you
can use the __fastcall keyword whenever you would have passed arguments
in registers.

The syntax for using the __fastcall keyword is:

ReturnType__fastcallFunctionName(Arguments);

Whenever you decide to use __fastcall, use it both
when declaring and when defining the function. As an introductory example of
using __fastcall, the following program uses two functions. The first
function, GetFullName() requests an employee’s first and last names, then it
returns the full name. Since this function is defined before being used, it was
not declared in the main() function. The second function, because defined after
main() (this was done on purpose), is declared in main() prior to using it. Both
functions use the __fastcall keyword. Notice that both functions have
their arguments also passed by reference. Here is the complete program:

We saw earlier that, when declaring a function, the compiler
needs to know only the name of the function, its return type and its type(s) of
argument(s), if any. We saw that, based on this ability of the C++
language, functions could be declared as follows:

The name of a function, its return type, and its list of
arguments, if any, is called the function's signature. This signature gives
complete information to the compiler regarding each function. The compiler needs
this information about each function because it creates a table (called a
virtual table) of all functions used in a particular file whether it is a header
file or a source file. When creating this table, the compiler assigns a unique
identification (like somebody's driver's license) to each function, using the
function's name, its return type, and its argument(s) (this allows the compiler
to perform name mangling).

When creating this table, the compiler uses each function's
name and its argument(s), if any:

If two functions have different names, they would have different
identifications, regardless of their argument(s), if any

If two functions have the exact same name and exact same type(s) or
argument(s), both functions would have the same identification, which would
result into a conflict (of course, you can use namespaces to prevent this
conflict)

If two functions have the exact same name but different argument(s),
either by the number of arguments or the type(s) of argument(s), they would
have different identifications.

The ability for two functions to have the exact same name
but differ either by their type(s) of argument(s) or by their number of
argument(s) allows the compiler to distinguish them. This is the foundation of
Function Overloading: Function Overloading is the ability to have various
functions that have the same name but different arguments, either by the number
of arguments of each function or by the types of arguments of each function.

The rea of the square is 232.562
The area of the rectangle is 291.042
Press any key to continue...

You can also declare overloaded functions as inline and/or __fastcall.

Practical Learning: Overloading Functions

The moment of inertia is the ability of of a beam to resist
bending. It is calculated with regard to the cross section of the beam. Because
it depends on the type of section of the beam, its calculation also depends on
the type of section of the beam: rectangular, triangular, circular, etc. In this
exercise, we will review different formulas used to calculate the moment of
inertia. Since this exercise is for demonstration purposes, you do not need to
be a Science Engineering major to understand it. The most important thing here
is the implementation of overloaded functions.

Here are the formulas to calculate the moment of inertia for a
semi-circle:

A circle and thus a semi-circle requires only a radius. Since the other
version of the MomentOfInertia() function requires two arguments, we can
overload it by providing only one argument, the radius.
To calculate the moment of inertia with regard to the X or base axis, in the
Inertia.h file, overload the MomentOfInertia() function as follows:

Enter the dimensions of the Rectangle
Base: 3.25
Height: 2.75
Moment of inertia with regard to the X axis: I = 22.5299mm
Enter the radius: 4.15
Moment of inertia of a semi-circle with regard to the X axis: I = 116.48mm
Press any key to continue...

After testing the program, return to Bcb

Here are the formulas to calculate the moment of inertia of a triangle:

As you can see, the rectangle and the triangle are using the same
dimension types. This means that, we can provide only the same kinds of
arguments, the base and the height, to calculate the moment of inertia. In
order to overload the MomentOfInertia() function, we will add an argument
that will never be used; this argument will serve only as a “witness” to
set the difference between both versions of the function. This “witness”
argument can be anything: an integer, a character, a string, a float, etc.
For our example, we will make it a simple integer. To use the version
applied to the triangle, we will provide this argument to overload the
MomentOfInertia() function. When called with only two arguments, the
rectangle version will apply.
To calculate the moment of inertia with regard to the X axis, in the
Inertia.h file, overload the MomentOfInertia function as follows:

Rectangle
Moment of inertia with regard to the X axis: I = 7671.78mm
Semi-Circle
Moment of inertia with regard to the X axis: I = 9344.28mm
Enter the dimensions of the triangle
Base: 4.55
Height: 2.75
Triangle
Moment of inertia with regard to the X axis: I = 7.88548mm
Press any key to continue...

After testing the program, return to Bcb

Conditional Statements and Functions

Using Conditions in Functions

The use of functions in a program allows you to isolate assignments and
confine them to appropriate entities. While the functions take care of
specific requests, you should provide them with conditional statements
to validate what these functions are supposed to do. There are no set
rules to the techniques involved; everything depends on the tasks at
hand. Once again, you will have to choose the right tools for the right
job. To make effective use of functions, you should be very familiar
with different data types because you will need to return the right
value.

The ergonomic program we have been writing so far
needs to check different things including answers from the user in order
to proceed. These various assignments can be given to functions that
would simply hand the results to the main() function that can, in turn,
send these results to other functions for further processing. Here is an
example:

Functions do not have to return a value in order to
be involved with conditional statements. In fact, both issues are fairly
independent. This means, void and non-void functions can manipulate
values based on conditions internal to the functions. This is
illustrated in the following program that is an enhancement to an
earlier ergonomic program:

A function defined other than void must always
return a value. Sometimes, a function will perform some tasks whose
results would lead to different consequences. A function can return only
one value (this is true for this context, but we know that there are
ways to pass arguments so that a function can return more than one
value) but you can make it render a result depending on a particular
behavior. Image that a function is requesting an answer from the user.
Since the user can provide different answers, you can treat each result
differently.

In the previous section, we saw an example of returning a value from a
function. Following our employment application, here is an example of a
program that performs a conditional return:

On paper, the function looks fine. If the user
answers with y or Y, the function returns the string Yes. If the user
answer with n or N, the function returns the string No. Unfortunately,
this function has a problem: what if there is an answer that does not
fit those we are expecting? In reality the values that we have returned
in the function conform only to the conditional statements and not to
the function. Remember that in if(Condidion)Statement;,
the Statement executes only if the Condition is true. Here
is what will happen. If the user answers y or Y, the function returns
Yes and stops; fine, it has returned something, we are happy. If the
user answers n or N, the function returns No, which also is a valid
value: wonderful. If the user enters another value (other than y, Y, n,
or N), the execution of the function will not execute any of the return
statements and will not exit. This means that the execution will reach
the closing curly bracket without encountering a return value.
Therefore, the compiler will issue a warning. Although the warning looks
like not a big deal, you should take care of it: never neglect warnings.
The solution is to provide a return value so that, if the execution
reaches the end of the function, it would still return something. Here
is a solution to the problem: