CISC 3142
Programming Paradigms in C++
Sample Programs
Program #1: Hello World
Write the classical Hello world
program
The Purpose
Traditionally, the first program illustrated in a programming language is one that displays the text Hello world
on the screen. It is
the program that programmers have traditionally run first, after installing the language's compiler and runtime on their machine, as a proof
of successful installation. It gained widespread recognition and acceptance after appearing in Kernighan & Ritchie's book
The C Programming Language
- Despite being relatively short, the program illustrates the basic structure of a program in the language.
- Input/output (which historically could be somewhat idiosyncratic to the language — in contrast to arithmetic expressions )
is illustrated.
Language Features
- basic program structure
- console-based output
- libraries and include (header) files
- namespaces
- program exit
1 #include <iostream>
2
3 using namespace std;
4
5 int main() {
6 cout << "Hello world" << endl;
7 return 0;
8 }
Lines
| Terms
| Notes
| In Java
|
1
|
- preprocessor
- library
#include
iostream
cout
|
- Preprocessor command to read the named library's (
iostream ) header file into the current source file
- The compiler copes the contents of the specified file (in this case
iostream and pastes it into the source file at the point of
the appearance of the #include
- The brackets (
<…> ) indicate that the file belongs to the Standard C++ Library, and the compile
knows where to find such files. Eventually, when you write your own such files, you will use quotes ("…" ) which will indicate
that fact to the compiler — such files will typically be in the same directory as the source file (there are ways of specifying other directories
as well).
- A header file would typically contain class declarations, global variables, non-member function declarations, and possibly other
information originating from other source files, but necessary for the compiler to translate the current source file.
- In this case, the library contains information about Input/Output streams, in particular the standard output represented
by the global variable
cout .
|
- Java has no preprocessor facilities, nor any other form of textual inclusion.
- The compiler 'knows' how to find the necessary files (generally class, but sometimes source) containing (class definition)
information necessary to translate the current file.
3
|
- namespaces
using
namespace
std
|
- Eliminates the need to preface various variables — typically known to the compiler by having
#include d them — with the name of the namespace.
- In this case, the namespace we're making implicit is
std which is the space of functions, variables,
classes, and other entities belonging to the C++ Standard Library
- Without the
using statement, one would have to refer to std::cout and std::endl
| Java's import statement has similar semantics in that it eliminates the need to specify full package names, i.e.,
java.util.ArrayList .
|
5-8
|
- non-member (C-style) function
main
|
- C++ programs may contain non-member functions; i.e., functions that do not belong to a class
- This is a derivative from C, and was retained to maintain backward-compatibility.
- C programs contain only non-member functions (there are no classes in C).
- C++'s program entry point is a non-member function named
main .
- This again maintains backward-compatibility with C. The function optionally accepts command-line arguments in
the form of a pair of parameters (more on that later), and returns a program
exit (i.e., status) code as its return value — hence the int return type.
|
- Java has no non-member functions — it's program entry point is a method named main in the class whose name is
provided as a command-line argument to the Java interpreter.
- Java's
main method's argument (String [] ) is mandatory, and it's return type is void
see below).
- The method is also declared
static as it is invoked as a method of the class (without any receiver — i.e., no object of the
class has yet been created).
|
6
|
- insertion operator
- operator chaining
cout
operator <<
endl
|
- Output is typically performed in C++ using the insertion operator,
<<
- The name derives from ts behavior: the right-hand operand (i.e., the value to be output — in this case
Hello world )
is inserted into the stream represented by the left hand operand (in this case cout .
- The
<< operator is heavily overloaded (in the output stream class) to provide output for C++'s predefined data types; in addition,
user-defined data types typically define their own overloaded version of << .
- The operator is defined in a manner that permits operator chaining, i.e., a succession of operations in which the result
of the previous is used as the left-hand operand of the next (e.g.
cout << 5 << "Hello" << endl .
- The object
endl represents the newline character; subsequent output begins on the next line.
- Using
endl also causes the stream to be flushed.
|
- Output in Java is typically done by invoking the single parameter
println method on the object System.out representing the standard output.
- The argument to the method is the value to be printed.
|
7
|
|
- By convention, a return value of 0 indicates a successful program execution; any other value typically indicates some form of error.
- A properly coded main function will typically contain a
return 0 at its end (and possibly other return statements
within the body of the function; for example in error-checking code).
|
- Java provides the method
System.exit that performs the same function.
- Since no return is necessary, (Java's
main returns to the JVM), Java's main method has a
return type of void .
| |
Program #2: Primes
Language Features
- conditionals and iteration
- functions and function headers
- console input
Prompt for and read an integer from the keyboard and print out all the primes up to that value
1 #include <iostream>
2 #include <cmath>
3
4 using namespace std;
5
6 bool isPrime(int);
7
8 int main() {
9
10 int howFar;
11 cout << "Generate all primes until? ";
12 cin >> howFar;
13
14 bool isFirst = true;
15 for (int i = 2; i <= howFar; i++)
16 if (isPrime(i)) {
17 cout << (isFirst ? "" : ", ") << i;
18 if (isFirst) isFirst = false;
19 }
20 cout << endl;
21 }
22
23 bool isPrime(int n) {
24 for (int i = 2; i <= sqrt(n); i++)
25 if (n % i == 0) return false;
26 return true;
27 }
Lines
| Terms
| Notes
| In Java
|
2
|
cmath
- C legacy header files
|
- being backward-compatible meant C++ programmers could use most of C's runtime libraries
- to make them more compatible with C++ naming, namespace, and other coding conventions, they
were wrapped within C++ friendly header files
- these files were prefixed with a
c to indicate their derivation from the
corresponding C library
cmath is thus derived from the C header math.h , and provides
mathematical function, such as sqrt
|
cmath corresponds loosely to Java's java.lang.Math class
|
6
|
|
- Just as a variable must be declared before use, the C++ compiler requires that a function be declared before it is called
- This allows the compiler to check the legality of the call, i.e., make sure the function exists, and is being called
with the correct number, types, and order of arguments.
- line 6 is known as a function header or function declaration; it consists
of the function's name, argument, and return type.
- This is in contrast to the function's definition which consists of the header followed
by the function's body (as seen in lines (
23-27 ).
- There are various conventions for organizing the function in a file; one common one is to place
main (if
the file contains a main ) first and then some logical (or random) ordering of the other functions after that.
- Since we are placing our functions after
main , which contains a called to isPrime
on line 16, , we place a function header in front of main .
- There will be no need to do this with member functions (functions that belong to a class.)
|
- This issue does not arise in Java
- Function headers are, however, reminiscent of Java's method declarations within an interface
12
|
|
cin is the input counterpart of cout
- Unlike Java,
cin is directly available for input
- The
>> operator is the input counterpart of the << (output) operator
| In Java, System.in must be passed to a Scanner constructor in order to be used for input.
|
14
|
|
bool is C++'s boolean type; more will be said about it late in the lecture on Imperative Programming
|
| |
Program #3: File Merge
Given files in1.data
and in2.data
that contain sequences of integers in sorted order, produce
a third file, out.data
resulting from merging the two sequences.
Language Features
- File I/O
- Opening, checking for successful open, closing, checking for successful read
- (string-based) exception handling
- program exit and exit codes
The Merge Algorithm
Merging two sorted files is fairly straightforward:
- set current position indexes to the beginning of both files
- compare the values at the current positions; the smaller value is written to the output file, and the corresponding current
position index is incremented to the next element
- repeat the above step until the end of one of the files is reached
- output the rest of the other file to the output file
Note that in this algorithm if the current values are equal, only one is written out to the output file; the other will participate in the next
comparison.
- One could make a modification that would write both equal values out; at a cost of complicating the algorithm
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <string>
5
6 using namespace std;
7
8 int main() {
9 try {
10 ifstream infile1("in1.data");
11 if (!infile1.good()) throw string("Cannot open in1.data");
12
13 ifstream infile2("in2.data");
14 if (infile2.fail()) throw string("Cannot open in2.data");
15
16 ofstream outfile("out.data");
17 if (!outfile) throw string("Cannot open out.data");
18
19 int i1, i2;
20
21 infile1 >> i1;
22 infile2 >> i2;
23
24 while (!infile1.eof() && !infile2.eof())
25 if (i1 < i2) {
26 outfile << i1 << " ";
27 infile1 >> i1;
28 }
29 else {
30 outfile << i2 << " ";
31 infile2 >> i2;
32 }
33
34 while (!infile1.eof()) {
35 outfile << i1 << " ";
36 infile1 >> i1;
37 }
38
39 while (!infile2.eof()) {
40 outfile << i2 << " ";
41 infile2 >> i2;
42 }
43
44 infile1.close();
45 infile2.close();
46 outfile.close();
47
48 return 0;
49 } catch(string message) {
50 cout << message << endl;
51 exit(1);
52 }
53 }
Lines
| Terms
| Notes
| In Java
|
2
|
|
- C++'s runtime has a library containing a hierarchy of classes for I/O.
fstream is the header
that provides classes for file streams
|
- This corresponds loosely to portions of the
java.io package
- Java has a similar hierarchy in its
java.io package; in particular the classes FileInputStream ,
FileOutputStream , etc
|
10-17
|
ifstream , ofstream
fail , good , !
exit
cstdlib
|
ifstream represents a file stream for input; ofstream is for output
- streams are opened by supplying the file names to the constructor
- We will discuss constructor syntax and semantics in more detail later; for the moment, the arguments to
the constructor are provided in a parenthesized list after the variable name.
- There are three (slightly different) presentations of standard logic for opening files
- Unlike Java, C++ does not throw an exception if a file can't be opened; it is the programmer's responsibility
to check that situation
- We present three 'equivalent' ways of doing the check, using two functions and an operator:
good — return true if no error has occurred
fail — return true if an error has occurred
! — return true if an error has occurred (same as fail )
- If the file could not be opened, a diagnostic is printed and the program exited
- Since we are in
main we could have simply done a return ; however in general, to
exit the program from anywhere, we use the function exit , obtained from the cstdlib
library
|
- Java does its own checking for a successful open and throws and exception on failure.
exit corresponds to Java's System.exit method
|
11, 14, 17, 9, 49-51,
|
- exception handling
string(…)
|
- C++'s exception handling mechanism is similar to Java's in terms of the semantics of
try , throw and catch
- C++, however, permits a much wider set of types that can be used to throw an exception.
- In fact, any type can be used as the exception object.
- In our case, we are throwing
string s containing a descriptive message for our exceptions,
- The actual type of a string literal (
"…" ) is a (constant) array of char , which is different than the string ,
so we create a string from it via the string constructor (which acts as a cast of sorts).
- We could have thrown the 'naked' string literal, but that would mean having to specify its type in the
catch , and it as involves unfamiliar syntax (const char * ), we'll stick
with string for the moment.
- In C, a string is represented using a char array; in C++ such 'strings' are referred to as C-strings;
we will discuss them later on.
|
Program #4: Reversing an Array
Define a method that accepts an array and its size and reverses the elements of the array, as well as a main that tests the function on various arrays.
Language Features
- fixed-size arrays
const
c_str()
- some typical array initialization techniques
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <string>
5
6
7 using namespace std;
8
9 void reverse(int a[], int n);
10 void print(int a[], int n);
11 int load(string filename, int a[], int capacity);
12
13 int main() {
14 try {
15 const int A1_N = 10;
16 int a1[A1_N];
17 for (int i = 0; i < A1_N; i++)
18 a1[i] = i * 100;
19 print(a1, A1_N);
20 cout << endl;
21 reverse(a1, A1_N);
22 print(a1, A1_N);
23 cout << endl;
24
25 cout << endl;
26
27 int a2[] = {10, 12, 31, 47, 6, 8};
28 const int A2_N = sizeof(a2) / sizeof(a2[0]);
29 print(a2, A2_N);
30 cout << endl;
31 reverse(a2, A2_N);
32 print(a2, A2_N);
33 cout << endl;
34
35 cout << endl;
36
37 const int A3_CAPACITY = 100;
38 int a3[A3_CAPACITY];
39 int a3_size = load("numbers.data", a3, A3_CAPACITY);
40 print(a3, a3_size);
41 cout << endl;
42 reverse(a3, a3_size);
43 print(a3, a3_size);
44 cout << endl;
45
46 return 0;
47 } catch(string message) {
48 cout << "*** Exception *** " << message << endl;
49 exit(1);
50 }
51 }
52
53 void reverse(int a[], int n) {
54 for (int i = 0; i < n/2; i++) {
55 int temp = a[i];
56 a[i] = a[n-i-1];
57 a[n-i-1] = temp;
58 }
59 }
60
61 void print(int a[], int n) {
62 for (int i = 0; i < n; i++)
63 cout << a[i] << (i < n-1 ? ", " : "");
64 }
65
66 int load(string fname, int a[], int capacity) {
67 ifstream ifs(fname.c_str());
68 if (!ifs) throw fname + " not found";
69 int size = 0;
70
71 int num;
72 ifs >> num;
73 while (ifs) {
74 if (size == capacity) throw "array capacity exceeded";
75 a[size] = num;
76 size++;
77 ifs >> num;
78 }
79 return size;
80 }
Lines
| Terms
| Notes
| In Java
|
16, 27, 38
|
|
- The built-in array type derived from C has a fixed number of elements determined at compile-time,
- We will eventually introduce dynamic allocation which will allow arrays whose size is determined at run time
- The size (number of elements) in the array is included in the declaration of the array
- The empty brackets in the declaration in line 27 is a bit misleading … the compiler determines the number of elements
via the explicit initialization list
- So the array in line 27 is a fixed-size array of 6 elements
- leaving out the size is a convenience only; the following would be equivalent:
int a2[6] = {10, 12, 31, 47, 6, 8};
|
- In Java, an array is an object that needs to be (dynamically) created via
new
- Arrays are thus similar to class types, except they do not have methods.
- Array objects in Java are also fixed size
- Arrays — like other objects — are always accessed through reference variables
- 'Resizing' an array is actually a misnomer; what one is really doing is creating a new array object, copying over the values
from the old array object and having the reference variable shift its reference to the new array object
- When 'declaring' and creating an array in Java, e.g.
int [] arr = new int[100] , one is actually declaring a reference variable (whose type
is that of an integer array, arr , creating an array object (the int[100] ) and assigning its reference to arr .
|
15, 28, 37
|
|
- To avoid magic numbers scattered through the code, constant objects are employed for the sizes of the arrays
|
- This corresponds to Java's
final
|
15-18, 27, 37-39
|
|
- Three array initialization techniques are illustrated:
- the first initializes the elements of an array using a formula based on the index variable of a loop; in this case
i * 100
- the second uses an explicit initialization list. In this instance, the size of the array can be omitted and will be inferred by the compiler
(as mentioned above)
- the third initializes the array from file data.
- In the first two approaches, the array is fully populated, i.e., each element is assigned a value. In the third case, the array is declared
larger than the expected number of data items in the file, and as the array is filled (in the
load function), the number of elements
is maintained.
- The actual number of elements in the array is called its capacity or physical size,
while the number of elements actually assigned a value is called the size or logical size
- Arrays loaded in this manner, i.e., by reading data, are typically only partially populated
|
- These three array initialization techniques are used in Java as well
|
9-11, 53, 61, 66
|
|
- The declaration for an array parameter omits the number of elements; this permits arrays of arbitrary size to be passed to the function
- Arrays in C++ are relatively low-level objects, and do not maintain their length (or perform bounds checking), and thus the number of elements
needs to be passed to the function as well (in order to control any iteration through the array).
- The size, rather than the capacity is what is typically passed; the major exception is a function to initialize the array —
such as
load in this example — where the size has not yet been determined.
|
- As mentioned, arrays in Java are objects, possessing additional state and behavior in the form of a
length field and bounds checking.
- Though, even in Java, if an array is loaded via reading data, it will typically be only partially populated, and will thus
require a variable to maintain its (logical) size.
- … and this variable will have to be passed to any method processing only the populated portion of the array
- This (in addition to dynamic resizing) is another benefit to an
ArrayList
|
67
|
|
- Non-intuitively, the constructors (and
open method) of the fstream classes do not
accept a string for their 'file name' argument — the only acceptable type is the C-string mentioned above.
Given a string object, one can obtain the corresponding C-string version by calling the c_str
function of the string class.
|
Program #5: A Counter Class
Define a method that accepts an array and its size and reverses the elements of the array, as well as a main that tests the function on various arrays.
Language Features
- basic class
- constructor
- member initializer
c_str()
- some typical array initialization techniques
1 #include
2
3 using namespace std;
4
5 class Counter {
6 public :
7 Counter() : val(0) {}
8
9 void up() {val++;}
10 void down() {val--;}
11
12 int get() {return val;}
13
14 void print() {cout << val << endl;}
15
16 private:
17 int val;
18 };
19
20
21 int main() {
22 Counter c;
23 c.print();
24
25 for (int i = 1; i <= 5; i++)
26 c.up();
27 c.print();
28
29 for (int i = 1; i <= 6; i++)
30 c.down();
31 c.print();
32
33 while (c.get() != 0)
34 c.up();
35 c.print();
36
37 return 0;
38 }
Lines
| Terms
| Notes
| In Java
|
5, 38
|
- class definition/declaration
|
- This is an example of a class declaration that also contains the definition of the function bodies
- Function bodies are usually separated out and placed in a
.cpp , while the corresponding
declaration (i.e., the class header, member function headers, and data members) are placed in
a .h
- C++ uses a fairly static (and long-standing) compilation process; thus the name of the class has no bearing on the name of the source file
- Similarly, there is no notion of a public (nor private) class in C++
|
- Java uses a quite dynamic compilation and class-loading process and thus requires the name of a public class to match the
name of the source file
- For the same reason Java permits the notion of a public vs private class; i.e., whether the class is visible from another
class (or outside the package).
|
7
|
|
- C++ provides a syntax specific to constructors, call a member initializer list for the initialization of
the class' data members. The format is a list of initializers, each consisting of a data member followed by an initializing expression.
- The most common initializing expressions are either one of the parameters passed to the constructors, or a constant (in our example
the
val data member is initialized to 0). However, and arbitrary expression (whose variables are scoped at that point) would be legal.
(For example, dynamically-allocated array data members are often allocated (using new here).
- Although a nice self-documenting notation in its own right, this syntax is necessary when composition
and/or inheritance is being used.
- If they are not present, one could initialize the data members as in Java; i.e., in the constructor body,
but using a member initializer list is the preferred method even then.
|
- As will be discussed later, Java has no need for this syntax. Java's instance variable initialization occurs within the body of the constructor.
|
6, 16
|
|
- C++ provides data encapsulation via public and private declaration. These are placed independently of any actual variable or function
declaration, and are followed by a ':'.
- All variables following such a 'label' (until the next such label) have the corresponding data access.
- By default (i.e., if no public or private is placed at the beginning of the class body), data access is private.
|
- Java requires public and private on the individual declarations.
|
Compiling From the Command Line
We will have much more to say about the software development cycle later, but for the moment, just a brief overview of
compiling and executing C++ programs. If you are in an IDE, you will probably be using menu commands; the following just illustrates the basic
sequence from the command line.
- To compile a C++ source file:
weiss> g++ <filename>
for example,
weiss> g++ primes.cpp
- To execute the program, launch the executable file name:
weiss> a.out