February 02 (Monday) February 06 (Friday)
A brief note about the C++ lectures:
We will be following the C++ textbook, Koenig & Moo (K&M), much more linearly than we did K&R. Also note that most (but not all) of the examples that we'll be using for C++ are directly from K&M. You can find a copy of the text on reserve in the library if you did not buy a copy from the bookstore. You can download all the source code from the text from the book's website. The online notes provide a summary of the material in the book. You should read the book in order to get more detailed descriptions of the concepts presented in these notes.
Hello world!
program in C++ (review) (K&M Chapter 0)
We've already seen the C++ version of the Hello world!
program
on the first day of lectures:
#include <iostream>
int main()
{
std::cout << "Hello world!" << std::endl;
return 0;
}
hello.cpp
We can compile the program and generate an executable similar to the method we used earlier for compiling C programs:
$ g++ -o hello -Wall -ansi -pedantic hello.cpp $ ./hello Hello world! $
Better still, we can use a simple Makefile
to make
compiling C++ programs less tedious:
CXXFLAGS = -g -Wall -ansi -pedantic
Makefile
Notice the Makefile
uses CXXFLAGS
to
pass command line options to the C++ compiler. For C, we used
CFLAGS
to perform the same function. Unfortunately,
most of the machines in the Computer Science department currently
have an old version of g++
installed on them (v2.96).
This version of the compiler has some limitations with respect
to namespaces (described below) and should not
be used to compile your C++ programs. Machines in the senior CS
lab that currently have a more recent version of g++
installed (v3.x) include bombadil
,
bombur
and
boromir
. More machines with this version
of g++
may become available in the future. When compiling
your C++ programs, you must use one of these machines. Note that you can
ssh
to one of these machines from another machine and do your
compilation remotely (make sure that the remote machine is turned on).
For example:
faramir$ ssh bombur bombur$ cd comp3710 bombur$ cat hello.cpp #include <iostream> int main() { std::cout << "Hello world!" << std::endl; return 0; } bombur$ cat Makefile CXXFLAGS = -Wall -ansi -pedantic bombur$ make hello g++ -Wall -ansi -pedantic hello.cpp -o hello bombur$ ./hello Hello world! bombur$ ... bombur$ exit faramir$ exit
.cpp
extension, although
this is may be compiler dependent. The sample code for the book actually
uses .cc
to signify C++ files. For this course, we will
use the .cpp
extension.
std::cout
object, which is defined in the C++ standard library, to
write data to standard output. This is roughly analogous to C's
printf()
function. The std::cout
object is
of type std::ostream
which is a class defined in the C++
standard library. std::endl
causes the output buffer to
be flushed and a newline to be written to the display. We'll be talking
more about object-oriented programming in future lectures.
main()
function is int
.
However, if you don't explicit return
a value from your
main()
function, 0
will will be returned by default
-- this is different from C.
//
which treats everything after it (up to the newline) as a
comment. Or you can delimit your comments with
/*
...*/
(like C).
<iostream>
header included by
the program. You must include this header if you want to use
input/output objects such as std::cout
. This is analogous
to the <stdio.h>
header file in C. However, there
is no .h
on the header name. iostream
may or
may not be an actual file on the filesystem. How a C++ compiler
defines its headers depends on the compiler manufacturer.
A namespace is simply a collection of related names. The purpose of
a namespace is to prevent naming conflicts which can arise in large
programs. For example, if libraries supplied by two different vendors
both contained a function called func()
, then, provided
that each vendor placed the function in different namespaces, you can
use both versions without having to worrying about naming conflicts.
The most common namespace is the standard library and is denoted by the
std
namespace, as seen in the program above.
To access a type or object inside a namespace, we use the namespace's
name in conjunction with the scope resolution operator (::
)
Therefore, to access the cout
object in the std
namespace, we write:
std::cout
Note! In g++
v2.96, the standard
library names are automatically placed in the global namespace. This is
nonstandard behaviour. This bug is fixed in g++
3.x
which, unfortunately, is not yet available on all CS machines. Please use
one of the machines mentioned above to compile your C++ programs.
Some C++ books use the using
directive in order to
import the entire std
namespace, as demonstrated
by the following program:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world!" << endl;
return 0;
}
hello3.cpp
This allows us to write cout
and endl
instead
of std::cout
and std::endl
. While this may seem
to be a better way to write our C++ programs, many purists argue that this
is not a wise thing to do as it imports all the symbols from the
std
namespace, thereby causing the pollution of the
global namespace. This could result in collisions between your types
and objects and the types and objects defined in the std
namespace. Therefore, when referencing entities in the standard library
such as cout
you should either qualify all such references
with std::
or, as we'll see later, you can limit the
symbols imported from the standard namespace.
Incidentally, the same Makefile
given above can be used to
compile both the above programs.
cout
and the <<
operator
We've already seen bitwise operators in C and they exist in C++ as
well. <<
, >>
, |
,
&
and ^
are the left shift, right shift,
bitwise or, bitwise and and bitwise xor,
respectively. C++ overloads the <<
operator to do
output when the first operator is of type std::ostream
.
Therefore, the statement:
std::cout << "Hello world!" << std::endl;
simply writes the string literal "Hello world!"
to the
standard output. Note that the <<
operator is left
associative.
(std::cout << "Hello world!") << std::endl;
This means that when applying the <<
operator to
std::cout
and a string, the return value is another
object of the same type as std::cout
(i.e.
a std::ostream
type). This value is then used as the
first operand for the second <<
operator and the
std::endl
operand.
C++ has much better for support for strings than C. However, the core C++
language does not define a native string type per se. Instead,
the Standard C++ Library provides a comprehensive string
class. For example, consider the following program which inputs
a string from the user and displays a greeting for that user:
// ask for a person's name, and greet the person
#include <iostream>
#include <string>
int main()
{
// ask for the person's name
std::cout << "Please enter your first name: ";
// read the name
std::string name; // define `name'
std::cin >> name; // read into `name'
// write a greeting
std::cout << "Hello, " << name << "!" << std::endl;
return 0;
}
greet.cpp
This program introduces the standard string
type.
In order to use strings in C++, we must #include
the
<string>
header. The program also demonstrates how
to do input using the std::cin
object and the right shift
operator (>>
).
std::string name; // define `name' std::cin >> name; // read into `name'
Note that when inputting a string,
the >>
function will only input a single word.
(i.e. it will skip over any leading whitespace, and read the
non-whitespace characters until it hits another whitespace character,
at which point it will stop reading). So, for example, if we input the
string two words
, the output will be Hello two!
Note that unlike C, we no longer have to worry about low-level
details such as ensuring we have enough space inside the string to
store all the characters. Nor do we have to worry about the nul byte.
The string
library takes care of all of those details for us!
The string literal "Hello, "
and the string
variable name
and a !
are all displayed using
std::cout
which we saw earlier.
We can make the example a little more complicated by displaying a frame around the greeting as demonstrated by the following program:
// ask for a person's name, and generate a framed greeting
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter your first name: ";
std::string name;
std::cin >> name;
// build the message that we intend to write
const std::string greeting = "Hello, " + name + "!";
// build the second and fourth lines of the output
const std::string spaces(greeting.size(), ' ');
const std::string second = "* " + spaces + " *";
// build the first and fifth lines of the output
const std::string first(second.size(), '*');
// write it all
std::cout << std::endl;
std::cout << first << std::endl;
std::cout << second << std::endl;
std::cout << "* " << greeting << " *" << std::endl;
std::cout << second << std::endl;
std::cout << first << std::endl;
return 0;
}
frame01.cpp
We can run this program as follows:
$ ./frame01 Please enter your first name: Estragon ******************** * * * Hello, Estragon! * * * ******************** $
This program demonstrates several new features:
Like Java, we can concatenate strings in C++ using the// build the message that we intend to write const std::string greeting = "Hello, " + name + "!";
+
operator. We can concatenate string
variables with
string literals, but, as we will see later, we cannot concatenate
two string literals using +
. Again, we do not have to
worry about ensuring that the destination string
variable
has enough memory to store all the characters in the string -- the
string
class will take care of that for us. The above code
fragment also demonstrates that we can initialize a string
variable. Note also that greeting
is a const
variable. We must give name
it an initial value and cannot
change it after that. const
is similar between C++ and C.
const std::string spaces(greeting.size(), ' '); const std::string second = "* " + spaces + " *";
The above code fragment demonstrates two ways that we can construct a
string object. The second way given above (using the =
sign)
is similar to what was used earlier. The first statement of the above
code fragment is building a string
object by calling a method
that takes a number n, for example, and a character c.
It will create a string of length n in which all the characters
are c. In the example above, spaces
will be a
string that contains n spaces, where n is the number
of characters in the string greeting
.
strlen()
function to determine
how many characters are in a string like we did in C, we use the
size()
method (or member function) of the string class.
Therefore in order to determine how many characters are in the
name
string, we write greeting.size()
.
char *
and strings
With respect to strings in C++, note that we can still use
char*
in C++. However, we cannot treat them the
same way as the C++ string
library type. Consider
the following example:
#include <iostream>
#include <string>
int main()
{
char *p = "Hello";
std::cout << p + " world" << std::endl;
return 0;
}
concat.cpp
In this example, we are trying to concatenate a char*
to
a string literal. Unfortunately, this does not work as expected. In
fact, it doesn't even compile successfully. If we wanted to concatenate
them using the +
operator, then at least one (or both)
of them will have to be converted to a string
. We can
do this as follows:
std::cout << std::string(p) + " world" << std::endl;
Now the string concatenation will occur as expected. We could also have done the following:
std::cout << p + std::string(" world") << std::endl; std::cout << std::string(p) + std::string(" world") << std::endl;
We'll learn more about why this works when we talk about type conversions and operator overloading.
Last modified: February 9, 2004 00:41:27 NST (Monday)