(3) cpp procedural programming
-
Upload
nico-ludwig -
Category
Technology
-
view
119 -
download
1
description
Transcript of (3) cpp procedural programming
Nico Ludwig (@ersatzteilchen)
(3) Basics of the C++ Programming Language
2
TOC● (3) Basics of the C++ Programming Language
– Procedural Programming
– Predefined and User defined Functions
– Declaration and Definition of Functions
– Procedural and recursive Function Calling
– Namespaces and separated Function Definitions
– A Glimpse of Separated Compilation and Translation Units
● Sources:– Bruce Eckel, Thinking in C++ Vol I
– Bjarne Stroustrup, The C++ Programming Language
3
Procedural Programming● Imperative programming reaches its limits very soon.
– It is needed to repeat identical code parts all over in the program.
– If a repeated part contains a bug, this bug is present on all occurrences!
– We have to copy a code part to reuse it, or to share it with other developers.
– In general: Don't Repeat Yourself! DRY
– DRY in programming results in the the "Top-Down" approach.
● In engineering, complex problems are getting separated into smaller problems.– In programming, problems are broken into procedures or functions.
– We call this the "Bottom-Up" approach, or functional decomposition.
● Procedural programming is all about the "Top-Down" and "Bottom-Up" notions.– Top-Down: Programmers rework their code into functions to make it reusable.
– Bottom-Up: Programmers code new functions that solve subproblems.
● Procedural programming extends imperative programming with the concept of (reusable) functions.
4
Procedural Programming in C/C++● In C/C++, procedural programming is implemented with functions.
● A function is a part of code that can be called independently.– Formerly known as "sub program".
– In C/C++ there is no difference between procedures and functions.
– In functions, statements can be executed imperatively.
– In functions, further functions can be called as well.
● This code style is rather verb-oriented: "do this" and "call that" etc.
● Procedural code in C/C++:– Program execution starts in the function main(), from where other functions are being called.
– In fact coding functions is the central activity of C/C++ programmers!
5
Using predefined Functions in own Code● The C/C++ standard library provides a plethora of functions for us.
– The C/C++ standards team already had their "Top-Down" specs on... :-)
– These functions allow reusing foreign code to solve own problems.
– E.g: std::pow(), std::qsort(), std::bsearch(), std::transform() etc.
– Some functions open the gate to the OS, like std::system().
● How to use functions from the standard library?– #include the respective standard h-file, where the function declaration resides.
– (Optionally add a using directive for the namespace std.)
– Call the standard function within own code.
– (Mind to pass the lib file, where the functions' definition resides, to the linker.)
6
Declaration and Definition of Functions
int GetCount (int x, int y)
{ // A block of code (function body).
}return 42;
Type of returned value or void. Function name Parameter list
Function bodyReturn value from function.
int GetCount (int x, int y = 0);Declaration:
Definition:
C++11 – trailing return typeauto GetCount(int x, int y) -> int {
return 42;}
int (*)(int, int)
The signature of GetCount.
Default argument
7
Features of Functions – Returning Values● Functions can have a return type.
– When such a function is called, a value of type "return type" will be returned as a result of that function.
– This value can be stored (stuck into a variable) or otherwise consumed.
● Functions w/o return type are declared as returning void instead of a concrete type.
– Such functions don't have a result, but a persistent side effect in most cases.
● Functions, which only return values but have no side effects, are sometimes called pure functions.
● When a return statement in a function is executed (w/ or w/o returning a value) a function will be exited immediately!
// Store the returned value in a variable... (Mind that we have to write a pair of empty// parentheses, as GetDayOfMonth() accepts no parameters.):int day = GetDayOfMonth(); // …or use it in an expression:std::cout<<"The day is: "<<GetDayOfMonth()<<std::endl;// Finally the function can be called, ignoring the result: GetDayOfMonth();
// On calling ClearScreen(), the side effect happens, then ClearScreen() returns.ClearScreen(); // However, ClearScreen dos not return a value we could process!
// A function, which returns an int.int GetDayOfMonth() {
// pass}
// Clears the screen as side effect,// but doesn't return a value.void ClearScreen() {
// pass}
8
Features of Functions – Parameters● The return type, the parameter types and the order of parameters make up the signature of a function.
● Function definition and declaration can have an optional list of parameters (params).– A parameter is a function's variable storing the value of the passed argument.
– A set of functions can have the same name, but differ in the signature's parameter list.
● This handy feature is what we call "function overloading".
– The last items of the parameter list can be prepared with default arguments or build a variable argument list.
● On calling a function a list of arguments will be passed to satisfy the params.– If a function requires no parameters, an empty pair of parentheses is written.
– Order and type of the arguments must match to the parameters respectively.
● By this matching, the correct (overloaded) function will be found.
● A matching (overloaded) function is resolved at compile time!
– Parameters having a default argument, need not to be "satisfied".
– Arguments are passed by value by default, so parameters contain copies of the arguments.
9
Features of Functions – Calling them in a Nutshell
// Call ClearScreen() (mind the pair of empty parentheses), ClearScreen() should// perform a side effect.ClearScreen();
// Call CheckAccount(), pass 42 as argument.CheckAccount(42);
// Call GetEntry(), pass 4 as argument, store the returned result in the variable theEntry.int theEntry = GetEntry(4);
// Call GetValue(), pass 7 (trackId) and then 7 (trackId) and 4 (index). Result ignored.GetValue(7); // The parameter index defaults to 0.GetValue(7, 4); // Both parameters are being satisfied.
void ClearScreen(); // No return type, no parameter list.
void CheckAccount(int accountId); // No return type, awaits an int parameter.
int GetEntry(int entryId); // Returns int, awaits an int parameter.
int GetValue(int trackId, int index = 0); // Returns int, awaits two int parameters.
10
Functions are called – there is no Code Replacement● A common misunderstanding: function call leads to code replacement.
– This is not what's going on!
● The functions A() and B() do always exist, their code is not merged somehow.
● Functions are rather procedurally called in C/C++.
● (Code replacement can be achieved with macros in C/C++.)
int A() {return 2 + 3;
}
void B() {int result = A();std::cout<<result<<std::endl;
}
void B() {int result = 2 + 3; // No!std::cout<<result<<std::endl;
}NO!
11
Procedural Calling of Functions● And again: functions can call other functions.
– When a function completes, execution returns to where the function was called from.
– "Top-level" functions call "lower-level" functions. So, there is a call hierarchy.
int main(int argc, char* argv[]) {double result = Square(3);
}
#include <cmath>
double Square(double arg) {return std::pow(arg, 2);
}
namespace std {double pow(double b, double exp) {
// calculate the powreturn value;
}}result = 9
(3)
(3, 2)
9
9
12
Recursive Calling of Functions● Some problems can be described as smaller instances of the same problem.
– In maths such descriptions are called recursive descriptions.
– For example the factorial function (1 x 2 x 3 x 4 … x n):
● Factorial can be expressed as a recursive function in C/C++.– In maths, recursion means that a equation is defined in terms of itself.
– In programming, recursion means that a function calls itself.
● How to write a recursive function?– A subproblem of the whole problem must be used as argument for recursive calls.
– And it is needed to consider the base case, when the recursion terminates!
– (The progression of the recursive calls must tend to the base case.)
– If we fail to consider one of these cases, we may end with an infinite recursion!
n!={1; n=0n((n−1)!); n>0
n∈N
13
Recursive Calling in Action
int main(int argc, char* argv[]) {int result = Factorial(3);
}
int Factorial(int n) {if (0 == n) {
return 1;} else {
return n * Factorial(n – 1);}
}
int Factorial(int n) {if (0 == n) {
return 1;} else {
return n * Factorial(n – 1);}
}
(3) (2)
62
int Factorial(int n) {if (0 == n) {
return 1;} else {
return n * Factorial(n – 1);}
}
(1)
1
int Factorial(int n) {if (0 == n) {
return 1;} else {
return n * Factorial(n – 1);}
}
(0)
1
0 == n
result = 6
14
Various Implementations of the Factorial Algorithm
int FactorialRecursive(int n) {if (0 == n) {
return 1;} else {
return n * FactorialRecursive(n – 1);}
}int FactorialIterative(int n) {
int result = 1;for (int i = n; i > 0; --i) {
result *= i;}return result;
}int FactorialNiceRecursive(int n) {
return (0 == n)? 1: n * FactorialNiceRecursive(n - 1);
}
n!={1; n=0n((n−1)!); n>0
n∈N
15
Recursion and Recursive Functions in the Wild● Useful to operate on recursive data. -> Data trees!
– E.g. a TreeView contains trees, that contain subtrees, that contain subtrees...
– Xml data is also a cascading tree of trees.
– Directory and file hierarchies.
– Network analyses, e.g. calculation of network efficiency and network load.
● Complex problems and puzzles can be solved easily with recursion.– Maths: permutations of a set, numeric differentiation/integration
– Games: Towers of Hanoi, Sudoku, Chess puzzles etc.
● Definition of subproblems to be solved by multiple CPUs independently.– The idea is to use CPU resources most efficiently -> Divide and conquer!
– Filters in graphics programming.
– Data analyses in networks and databases.
16
Organizing Functions in Namespaces● So far all user defined functions we saw, were defined as global functions.
● Global functions may clash with equally named/typed other functions.– The functions of the standard library reside in the namespace std to prevent this.
● Also do namespaces group free functions semantically.– It turns out, that all free functions should reside in namespaces!
– Don't define global functions (save main()), use namespaces instead!
● C++ namespaces can be understood as directories and functions as files.– In a file system directories do contain files.
– Files with the same name can reside in different directories. -> No clash!
● Let's examine how to define and use namespaces with the function Factorial()...
17
// Function Factorial in the namespace Nico:namespace Nico {
int Factorial(int n) {return (0 == n)
? 1: n * Factorial(n - 1);
}}
Defining and using Namespaces in Code
// 1. Alternative: Qualify the function name// with the namespace's name:int main(int arc, char* argv[]) {
int result = Nico::Factorial(3);return EXIT_SUCCESS;
}
// 2. Alternative: Make all functions// in the namespace Nico global: with a// using directive:using namespace Nico;int main(int arc, char* argv[]) {
int result = Factorial(3);return EXIT_SUCCESS;
}
// 3. Alternative: Make only functions// named Nico::Factorial global: with// a using declaration:using Nico::Factorial;int main(int arc, char* argv[]) {
int result = Factorial(3);return EXIT_SUCCESS;
}
18
Separated Function Definitions● Related functions should be implemented in separate code files. - Why that?
– Each developer can manage just his functions, not interfering with others'.
– On modification, just the separately modified code files must be compiled.
– Very important: The implemented code can be hidden from its callers.
● Separate and collect function definitions. - What's to do?– Collect related function definitions in own cpp/c-files (summarized "c-files", these are the code files).
– Create h-files with function declarations for the functions in the c-files respectively.
– These "matching" h- and c-files should have the same name.
● The file names should not contain whitespaces or special characters (like umlauts).
– As C/C++ convention, #include the h-files into the belonging cpp/c-files.
● Calling the separated functions. - What's to do?– In our top-level code file, we've to #include the h-files declaring the functions we need.
– In the code we can call the functions, because the declarations are visible.
19
Documentation of Function Declarations● The separation of function declaration and definition leads to information loss.
– In some sense this was the aim (callers should not see the definitions).
– But the mere function declaration is very opaque to us.
● How to improve the situation?– Self description: Choose meaningful function and parameter names.
– Add documentation/usage comments to function declarations.
// numeric.hnamespace Nico {
/// Calculates the factorial./// @param arg – the positive value to calculate the factorial from./// @return – the factorial result.int Factorial(int arg);
}
20
Creation of the Translation Unit by the Preprocessor
// numeric.hnamespace Nico {
/// Calculates the factorial./// @param arg – the positive value/// to calculate the factorial from./// @return – the factorial result.int Factorial(int arg);
}
// Main.cpp#include "numeric.h"int main(int arc, char* argv[]) {
int result = Nico::Factorial(3);return EXIT_SUCCESS;
}
// Main.cpp tunamespace Nico {
int Factorial(int arg);}
int main(int arc, char* argv[]) {int result = Nico::Factorial(3);return EXIT_SUCCESS;
}// numeric.cpp#include "numeric.h"
namespace Nico {int Factorial(int n) {
return (0 == n)? 1: n * Factorial(n - 1);
}}
21
Separated Compilation and Linkage● The separated c-files with function definitions need to be compiled also!
– In simple projects, we'll only have one code file (with the definition of main()).
– But in multi-file-projects we need to tell the compiler to compile all!
– Also the linker has to link all the resulting object-files (o-files) to an executable.
● How to negotiate with the compiler and linker about multiple files?– We can, however, compile all c-files separately, e.g. on the console.
– We can write a make file that defines the build-tasks for compiler and linker.
– => In the end it is recommended to use an IDE to define this stuff in a project.
● Ok! What does a project within an IDE do for us?– In the project we'll just collect all the h/c-files (and other files) we require.
– The IDE project will be automatically updated, when we add/remove h/c-files.
– Compiler and linker will be automatically prepared to deal with all the project's files.
22
Getting our Feet wet with IDE Projects and Functions● Example – Decompose a problem:
– Often the function call std::system("pause") is used to wait for the user on console.
– Possibly this function call should be used by other programs as well.
– That solution is Windows only! It should be expressed by platform neutral means.
– Let us extract this into our own function the "Bottom-Up" way! → Call it Wait().
– We should put this new function into its own namespace!
– Implement with std::system("pause") and test it.
– Then implement it in a platform neutral fashion and test it again.
– => Decomposition complete!
23
Thank you!