Pointers and Arrays - University of Oxford

Download Report

Transcript Pointers and Arrays - University of Oxford

More on functions



We can declare a function to have more than one
signature but the same name.
This is called overloading, some languages refer
to this as polymorphism
See Overload1.cpp




Set as exercise:
//write a program that overloads the function
Findroots(int, int, int)
FindRoots(double, double, double)
For finding the roots of a quadratic equation.
Overloading functions



The compiler creates two such functions
which are different even though they have the
same name.
The compiler knows which function to invoke
by the parameters that are being passed to it.
FindRoots(2.1,2,4,-4.5) will invoke the
function expecting doubles.
Pointers
A variable in a program is something with a
name, the value of which can vary. The way the
compiler and linker handles this is that it
assigns a specific block of memory within the
computer to hold the value of that variable.
The size of that block depends on the range
over which the variable is allowed to vary. For
example, on 32 bit PCs the size of an integer
variable is 4 bytes. On older 16 bit PCs integers
were 2 bytes.
Pointers and Arrays
What is a pointer?
One of those things that people find
difficult in C/C++ is the concept of pointers.
The purpose of this power_point is to
provide an introduction to pointers and
their usage.
One of the main reason why people have a
problem with pointers is that they have not
fully understood the concept of a variable,
(as they are used in C++). Thus we start
with a discussion of C++ variables in
general.
Pointers
In C/C++ the size of a variable type such as
an integer need not be the same on all
types of machines. Furthermore there is
more than one type of integer variable in
C++.
We have integers, long integers and short
integers which you can read up on in any
text on C++.
If you want to know the size of the various
types of integers on your system, running
the following code will give you that
information.
Pointers




#include <iostream>
using namespace std;
int main()
{
cout<<"size of a short is“<<sizeof(short)<< endl;
cout<< "size of an int is “ <<sizeof(int) << endl;
cout<< "size of a long is “<<sizeof(long) << endl;
return 0;
} //see sizeof.cpp //long same size as int
Pointers

When we declare a variable we inform the compiler of two things,
the name of the variable and the type of the variable. For
example, we declare a variable of type integer with the name k
by writing:
int k;
On seeing the "int" part of this statement the compiler sets aside
4 bytes of memory (on a PC) to hold the value of the integer.
It also sets up a symbol table. In that table it adds the symbol k
and the relative address in memory where those 4 bytes were set
aside.
Pointers






Thus, later if we write:
k = 2; we expect that, at run time when this statement is
executed, the value 2 will be placed in that memory location
reserved for the storage of the value of k.
In C++ we refer to a variable such as the integer k as an "object".
In a sense there are two "values" associated with the object k.
One is the value of the integer stored there (2 in the above
example) and the other the "value" of the memory location, i.e.,
the address of k.
Some texts refer to these two values with the nomenclature
rvalue (right value, pronounced "are value") and lvalue (left
value, pronounced "el value") respectively.
Pointers



In some languages, the lvalue is the value permitted on the
left side of the assignment operator '=' (i.e. the address
where the result of evaluation of the right side ends up).
The rvalue is that which is on the right side of the
assignment statement, the 2 above. rvalues cannot be
used on the left side of the assignment statement. Thus: 2
= k; is illegal.
Actually, the above definition of "lvalue" is somewhat
modified for C. According to K&R II (page 197): [1]
"An object is a named region of storage; an lvalue is an
expression referring to an object."
Pointers



However, at this point, the definition originally
cited above is sufficient.
Okay, now consider:
int j, k;
k = 2; j = 7; //line 1
k = j;
//line 2
Pointers






int j, k, k=2,j=7;
//line 1
k=j;
//line 2
In the above, the compiler interprets the j in line 1 as the
address of the variable j (its lvalue) and creates code to copy
the value 7 to that address.
In line 2, however, the j is interpreted as its rvalue (since it is
on the right hand side of the assignment operator '=').
That is, here the j refers to the value stored at the memory
location set aside for j, in this case 7.
So, the 7 is copied to the address designated by the lvalue of
k.
Pointers



In all of these examples, we are using 4
byte integers so all copying of rvalues from
one storage location to the other is done
by copying 4 bytes.
Had we been using two byte integers, we
would be copying 2 bytes.
Now, let us say that we have a reason for
wanting a variable designed to hold an
lvalue (an address).
Pointers




The size required to hold such a value depends on
the system.
On older desk top computers with 64K of memory
total, the address of any point in memory can be
contained in 2 bytes.
Computers with more memory would require more
bytes to hold an address.
The actual size required is not too important so
long as we have a way of informing the compiler
that what we want to store is an address.
Pointers





Such a variable is called a pointer variable (for
reasons which hopefully will become clearer a little
later).
In C++ when we define a pointer variable we do so
by preceding its name with an asterisk *.
In C++ we also give our pointer a type which, in
this case, refers to the type of data stored at the
address we will be storing in our pointer.
For example, consider the variable declaration:
int *ptr; //ptr will store the address of an
//integer
Pointers





ptr is the name of our variable (just as k was the
name of our integer variable).
The '*' informs the compiler that we want a pointer
variable, i.e. to set aside however many bytes is
required to store an address in memory.
The int says that we intend to use our pointer
variable to store the address of an integer.
Such a pointer is said to "point to" an integer.
However, note that when we wrote int k; we did not
give k a value
Pointer




If this definition is made outside of any function
ANSI compliant compilers will initialize it to zero.
Similarly, ptr has no value, that is we have not
stored an address in it in the above declaration.
In this case, again if the declaration is outside of
any function, it is initialized to a value guaranteed
in such a way that it is guaranteed to not point to
any C++ object or function.
A pointer initialized in this manner is called a "null"
pointer.
Pointer




The actual bit pattern used for a null pointer
may or may not evaluate to zero since it
depends on the specific system on which the
code is developed.
To make the source code compatible between
various compilers on various systems, we use a
null pointer.
The null pointer goes under the name NULL.
Thus, setting the value of a pointer using the
null pointer we use NULL, as with an
assignment statement such as
Pointers

ptr = NULL
guarantees that the pointer has become a
null pointer.
Similarly, just as one can test for an integer
value of zero, as in
if(k == 0), we can test for a null pointer using

if (ptr == NULL). //note uppercase



Pointers



But, back to using our new variable ptr.
Suppose now that we want to store in ptr the
address of our integer variable k. To do this
we use the unary &(ampersand) operator and
write:
ptr = &k;
ptr
k
Pointers





What the & operator does is to retrieve the lvalue
(address) of k, even though k is on the right hand
side of the assignment operator '=', and copies that
to the contents of our pointer ptr.
Now, ptr is said to "point to" k.
Now there is only one more operator we need to
discuss.
The "dereferencing operator" is the asterisk and it is
used as follows:
*ptr = 7;
Pointers



This will copy 7 to the address pointed to by ptr.
Thus if ptr "points to" (contains the address of) k,
the above statement will set the value of k to 7.
That is, when we use the '*' this way we are
referring to the value of that which ptr is pointing to,
not the value of the pointer itself.
ptr
K
7
Pointers
Similarly, we could write:
 cout << *ptr;
 to print to the screen the integer value stored at the
address pointed to by ptr.
 Lets run a program
UseofpointersinC++.cpp

Pointers and Array types





Okay, let us move on.
Let us consider why we need to identify the
type of variable that a pointer points to, as in:
int *ptr;
One reason for doing this is so that later,
once ptr "points to“ something, if we write:
*ptr = 2;
Pointers and array types



The compiler will know how many bytes to
copy into that memory location pointed to by
ptr.
If ptr was declared as pointing to an integer, 4
bytes would be copied.
Similarly for floats and doubles the
appropriate number will be copied.
More on pointers



But, defining the type that the pointer points
to permits a number of other interesting ways
a compiler can interpret code.
For example, consider a block in memory
consisting of ten integers in a row.
That is, 40 bytes of memory are set aside to
hold 10 integers.
Pointers and Array types




Now, let us say we point our integer pointer ptr at
the first of these integers.
Furthermore lets say that integer is located at
memory location 100 (decimal). What happens
when we write:
ptr + 1;
Because the compiler "knows" this is a pointer (i.e.
its value is an address) and that it points to an
integer (its current address, 100, is the address of
an integer)
Pointer and Array types





it adds 4 to ptr instead of 1, so the pointer "points to" the
next integer, at memory location 104.
Similarly, were the ptr declared as a pointer to a short, it
would add 2 to it instead of 1.
The same goes for other data types such as floats,
doubles, or even user defined data types such as
structures (which we discussed last week).
This is obviously not the same kind of "addition" that we
normally think of.
In C++ it is referred to as addition using "pointer arithmetic",
a term which we will come back to later.
Pointers

Similarly, since ptr++ is equivalent to
ptr + 1, incrementing a pointer using the
unary ++ operator, increments the address it
stores by the amount sizeof(type) where
"type" is the type of the object pointed to.
(e.g. 4 for an integer).
Pointers and Arrays



Since a block of 10 integers located
contiguously (along a line, or next to) in
memory is, by definition, an array of integers,
this brings up an interesting relationship
between arrays and pointers.
Consider the following:
int my_array[ ] = {1,23,17,4,-5,100};
Pointers and Arrays






Here we have an array containing 6 integers.
We refer to each of these integers by means of a
subscript to my_array, i.e. using my_array[0]
through my_array[5].
So that my_array[0] = 1, my_array[5] = 100
But, we could alternatively access them via a
pointer as follows:
int *ptr; ptr = &my_array[0];
/* point our pointer at the first */
//integer in our array
Pointers and arrays




And then we could print out our array either
using the array notation or by dereferencing
our pointer.
The following code illustrates this:
Run arrays_pointers1.cpp
Run arrays_pointers2.cpp
Pointers Arrays



Compile and run the above program and
carefully note lines A and B and that the
program prints out the same values in either
case.
Also observe how we dereferenced our
pointer in line B, i.e. we first added i to it and
then dereferenced the new pointer.
Change line B to read:
Pointers and Arrays
cout << "ptr + “<< i <<“ *ptr++;
and run it again... then change it to:
 cout << "ptr + i “ << *(++ptr);
 and try once more.
 Each time try and predict the outcome and
carefully look at the actual outcome.

Pointers and arrays





In C++, the standard states that wherever we might
use &var_name[0] we can replace that with
var_name, thus in our code where we wrote:
ptr = &my_array[0]; we can write:
ptr = my_array;
to achieve the same result.
So the array name is the base address i.e. address
of first element in the array.
Pointers and Arrays





This leads many texts to state that the name of an
array is a pointer.
Perhaps better to mentally think that "the name of
the array is the address of first element in the array".
Many people (including myself) have a tendency to
become confused by thinking of it as a pointer.
For example, while we can write
ptr = my_array;
Pointers and arrays





we cannot write
my_array = ptr;
The reason is that while ptr is a variable, my_array is
a constant.
That is, the location at which the first element of
my_array will be stored cannot be changed once
my_array[] has been declared.
Earlier when discussing the term "lvalue" I cited
K&R (Richie) - where it stated:
Pointers and arrays





"An object is a named region of storage; an lvalue is
an expression referring to an object".
This raises an interesting problem.
Since my_array is a named region of storage, why is
my_array in the above assignment statement not an
lvalue?
To resolve this problem, some refer to my_array as
an "unmodifiable lvalue".
Modify the example program above by changing
Pointers and arrays


ptr = &my_array[0]; to
ptr = my_array;
Pointers and Arrays




Now, let us delve a little further into the difference
between the names ptr and my_array as used
above.
Some writers will refer to an array's name as a
constant pointer.
What do we mean by that? Well, to understand the
term "constant" in this sense, let us go back to our
definition of the term "variable".
When we declare a variable we set aside a place in
memory to hold the value of the appropriate type.
Pointers and Arrays



Once that is done the name of the variable can be
interpreted in one of two ways.
When used on the left side of the assignment
operator, the compiler interprets it as the memory
location to which to move that value resulting from
evaluation of the right side of the assignment
operator.
But, when used on the right side of the assignment
operator, the name of a variable is interpreted to
mean the contents stored at that memory address set aside to
hold the value of that variable.
Pointers and Arrays



With that in mind, let us now consider the simplest of
constants, as in:
int i, k; i = 2;
Here, while i is a variable and then occupies space
in the data portion of memory, 2 is a constant and,
as such, instead of setting aside memory in the data
segment, it is imbedded directly in the code segment
of memory.
Pointers and Arrays




That is, while writing something like
k = i;
Tells the compiler to create code which at run time
will look at memory location &i to determine the
value to be moved to k, code created by i = 2;
simply puts the 2 in the code and there is no
referencing of the data segment.
That is, both k and i are objects, but 2 is not an
object.
Pointers and Arrays




This might be a good place explain further
the use of the
(void *)
expression which we can use.
As we have seen we can have pointers of
various types
Pointers and Arrays




So far we have discussed pointers to integers and
pointers to characters.
In coming lectures we will be learning about
pointers to structures and perhaps pointer to
pointers.
Also we have learned that on different systems the
size of a pointer can vary.
As it turns out it is also possible that the size of a
pointer can vary depending on the data type of the
object to which it points.
Pointers and Arrays



Thus, as with integers where you can run into
trouble attempting to assign a long integer to a
variable of type short integer, you can run into
trouble attempting to assign the values of pointers of
various types to pointer variables of other types.
To minimize this problem, C++ provides for a pointer
of type void.
We can declare such a pointer by writing:
Pointers and Arrays



void* vptr;
A void pointer is sort of a generic pointer.
For example, while C++ will not permit the
comparison of a pointer to type integer with a
pointer to type character, for example, either
of these can be compared to a void pointer.
Pointers and Strings



The study of strings is useful to further tie in
the relationship between pointers and arrays.
It also makes it easy to illustrate how some of
the standard C++ string functions can be
implemented.
Finally it illustrates how and when pointers
can and should be passed to functions.
Pointers and Strings






In C++, strings are arrays of characters.
This is not necessarily true in other languages.
In BASIC, Pascal, Fortran and various other languages, a string
has its own data type.
But in C++ it does not.
In C++ a string is an array of characters terminated with a
binary zero character (written as '\0').
To start off our discussion we will write some code which, while
preferred for illustrative purposes, you would probably never
write in an actual program. Consider, for example:
Pointers and Strings

char my_string[40];
my_string[0] = 'T';
my_string[1] = 'e';
my_string[2] = 'd':
my_string[3] = '\0';
Pointers and strings



While one would never build a string like this,
the end result is a string in that it is an array
of characters terminated with a nul
character.
By definition, in C++, a string is an array of
characters terminated with the nul character.
Be aware that "nul" is not the same as
"NULL". The nul refers to a zero as defined
by the escape sequence '\0'
Pointers and Strings


That is it occupies one byte of memory. NULL, on
the other hand, is the name of the macro used to
initialize null pointers. NULL is #defined in a header
file in your C++ compiler, nul may not be #defined at
all.
Since writing the above code would be very time
consuming, C++ permits two alternate ways of
achieving the same thing.
Pointers and Strings




First, one might write:
char my_string[40] = {'T', 'e', 'd', '\0',};
But this also takes more typing than is
convenient. So, C++ permits:
char my_string[40] = "Ted";
Pointers and Strings




When the double quotes are used, instead of the
single quotes as was done in the previous
examples, the nul character ( '\0' ) is automatically
appended to the end of the string.
In all of the above cases, the same thing happens.
The compiler sets aside an contiguous block of
memory 40 bytes long to hold characters and
initialized it such that the first 4 characters are
Ted\0.
Run pointers3.cpp
More on strings
char* my_strcpy(char dest[], char source[])
{
int i = 0;
while (source[i] != '\0')
{
dest[i] = source[i];
i++;
}
dest[i] = '\0';
return dest;
}
More on Strings




Recall that strings are arrays of characters.
Here we have chosen to use array notation instead
of pointer notation to do the actual copying.
The results are the same, i.e. the string gets copied
using this notation just as accurately as it did before.
This raises some interesting points which we will
discuss.
More on strings



Since parameters are passed by value, in both the
passing of a character pointer or the name of the
array as above, what actually gets passed is the
address of the first element of each array.
Thus, the numerical value of the parameter
passed is the same whether we use a character
pointer or an array name as a parameter.
This would tend to imply that somehow source[i] is
the same as *(p+i).
More on Strings





In fact, this is true, i.e wherever one writes a[i] it can be
replaced with *(a + i) without any problems. In fact, the
compiler will create the same code in either case.
Thus we see that pointer arithmetic is the same thing as
array indexing.
Either syntax produces the same result.
This is NOT saying that pointers and arrays are the
same thing, they are not.
We are only saying that to identify a given element of an
array we have the choice of two syntaxes, one using
array indexing and the other using pointer arithmetic,
which yield identical results
More on Strings


Now, looking at this last expression, part of it.
(a + i), is a simple addition using the +
operator and the rules of C/C++ state that
such an expression is commutative.
That is (a + i) is identical to (i + a). Thus we
could write *(i + a) just as easily as *(a + i).
More on Strings
But *(i + a) could have come from i[a] !
 From all of this comes the curious truth that
if:

char a[20]; int i;
writing

a[3] = 'x'; is the same as writing

3[a] = 'x';

More on Strings




Try it! Set up an array of characters, integers or
longs, etc. and assign the 3rd or 4th element a value
using the conventional approach and then print out
that value to be sure you have that working.
Then reverse the array notation as I have done
above.
A good compiler will not balk and the results will be
identical. A curiosity... nothing more!
Now, looking at our function above, when we write:
More on strings



Another way to speed up the pointer version
would be to change:
while (*source != '\0') to simply
while (*source) since the value within the
parenthesis will go to zero (FALSE) at the
same time in either case.
More on Strings





dest[i] = source[i]; due to the fact that array indexing
and pointer arithmetic yield identical results, we can
write this as:
*(dest + i) = *(source + i);
But, this takes 2 additions for each value taken on by i.
Additions, generally speaking, take more time than
incrementations (such as those done using the ++
operator as in i++).
This may not be true in modern optimizing compilers,
but one can never be sure. Thus, the pointer version
may be a bit faster than the array version.
More on Strings





At this point you might want to experiment a bit
with writing some of your own programs using
pointers.
Manipulating strings is a good place to
experiment. You might want to write your own
versions of such standard functions as:
strlen(); strcat(); strchr(); and any others you
might have on your system.
We will come back to strings and their
manipulation through pointers in a future lectures
//see stringlength.cpp
Introduction to Classes
Object Oriented Programming
C++ Classes

Class


A structured data type used to represent ADTs
Class member – a component of a class
data member
 function (method)
We can hide and bind different parts of the class structure
from other parts of the program. To do this we use the
reserved words public, private or protected (we will not
look at the protected interface in great detail at present).
This hiding is called encapsulation

Recall Structs


Separates implementation of data from
operations.
Structs are said to be passive in the sense
they just sit there and wait for something else
to do something to them.


Generally they do not have their own functions to
manipulate the data.
Structs are heterogeneous data structures, can
you recall why?
Classes






Are active in the sense that the data and operations and
bound together in one neat package.
Data operates on itself and interacts with other data.
A class has associated with it its own functions, these are
called methods in other languages e.g. Java
There is a public and private interface.
There is also a protected interface which we will
not dwell on in great detail.
There are also functions called friends
Class types


Like a struct a class is a programmer defined type written by the
programmer for the programmer.
It is not a data object of atomic type.
 But it can have attributes (the data) of atomic type. You create or
instantiate an object of a type, rather like creating a variable of
atomic type
 Think of the class type like a template the “builder” if you will.
 the objects are those things you build from the template. The
variables of that type.
Just like we have int x; is a declaration of an int variable
with label x, we can declare a variable of type class e.g
Time today, here the class name is Time and the object
name is today

class Time {
public:
void Set(int hours, int minutes, int
instantiate object A of type
seconds)
void Increment();
Time
void print();
int main() {
Time(int int Hours, int initMins,
Time1 A;
int initSecs);
return 0;
Time();
}
private:
int hours;
int mins;
int secs;
};
//See TimeClass2.cpp
//Look at displaydatestruct.cpp
//and discuss
The Constructor
Time::Time(){
cout << "Setting the time" << endl;
hour=0;
minute=0;
second = 0;
}
//note the constructor has the same name as the
//class itself. Note also it does not have a return
//type not even void
The constructor



Definition: The constructor is a member
function of a class.
It is invoked every time an object is created.
If no explicit constructors are defined, the
default constructor, which the compiler
provides is used.
Class Fundamentals



A class defines a new data type, from which
we can create objects (variables of this
class).
When we define a class, we can define both
the data and the code that operates on the
data.
A class declaration is similar to the struct
definition.
The structure of a class








class class-name
{ private data and functions
access-specifier:
data and functions
access-specifier:
data and functions ... ... ...
access-specifier:
data and functions } object-list;
An example of a class
class Employee {
private:
double wage;
int ID;
public:
void setID (int n);
int getID ();
void putwage (double w);
double getwage();
};
The class


A class is a logical abstraction, but an object
has physical existence.
access-specifier can be:



public: Allow functions or data to be accessible to
other parts of the program.
private: May be accessed only by other members
of the class.
protected: Used when inheritance is involved;
discussed later.
New terms



class is the keyword that begins a class declaration
By default members of a class are private to it, so if
we do not use an interface (i.e. public, private or
protected) the data become private, in a struct they
default to public (this is the main difference between
the two)
The public keyword is used to declare the public
members of the class
Objects



An object is like a variable only more
complex - it holds structured data and
exhibits certain behaviour.
The data access can be restricted (or
encapsulated). //new buzz word
The terms object and class are analogous to
the concepts of variables and datatypes
Objects



Objects are instances of a class.
The term instantiated is synonymous with
objects and classes.
It simply means to create a variable of that
particular class
Classes.
Consider a Student class, which defines
objects that have the following three
properties (accessible data):
 Registration number which is of type integer
 Name of type string
 Fees of type integer

The student class



We can create an instance of the Student
class using either of the following syntaxes:
Student st(1234, "Mary Smith", 2420);
Student st = Student(1234, "Mary Smith",
2420);
The default constructor






We can also use the default constructor (if there is one
defined for the class) as follows to create an instance of
Student that contains the default data:
Student st;
Note that Student st(); is not valid code.
It is possible to redefine the contents of an object using
an assignment statement.
For example, the following statement changes the
contents of the already-existing object:
st = Student(5678, "Bill Brown", 1320);
Encapsulation.



Not all the data stored in an object is accessible to
the outside world.
Access is defined by the object's member
functions which expose the data through the
object's interface.
For example the Student class could have



an accessor member function called get_number()
that defines access to the student's ID number as follows:
st.get_number(); // returns the ID number of the
//Student object st
More on encapsulation





reg_no = st.get_number();
//assigns the ID number to the variable //reg_no. i.e.
//places it in it
To access the properties and member functions of
an object, use the dot operator as shown above.
Objects can also have mutator member functions
that allow the properties to be modified.
For example, you could use the Student class's
set_name() function to change the name property of
a student:
Classes again


st.set_name("Betty Jones");
this would change the name of st from Bill
Brown to Betty Jones.
A closer look at Classes I




A typical function call looks like this:
x = sqrt(y);
A typical member function looks like this:
t = s.addnumbers(a, b);
Classes I


We know how to use objects, and in this
lesson we are going to learn how to create
them.
Just as variables are made of a particular
data type, for example char, int, double, so
objects are instances of a class.
Classes I




In C++ classes either
Come as standard to the language, for
example we have string objects or
are created by programmers.
Member functions (or methods) are defined
as part of the class definition.
A Basic Date class





We want our class to
represent the day and the month
not worry about leap years
At the most basic level we could simply use
two int variables to represent the day and the
month, but there would be no logical
correlation between them.
We want the two numbers to be conceptually
linked.
The Date class





To declare a class, use the class keyword and a
name.
By convention, class names begin with a capital
letter. //programmers decided this
The class declaration follows inside curly braces,
and ends with a semicolon after the closing brace.
The declaration defines the interface and the data
that the class will hold.
An interface defines the access (read, write or none)
you want the outside world to have some access to
an object's data and methods.
The Date class



The public interface comprises the data and
methods you want to expose to the outside
world; the private interface comprises the
data and methods you want to encapsulate or
hide from the outside world.
Encapsulated data and methods are by
default accessible only to other objects of the
same class.
You can also define friend functions, which
we illustrate later.
The Date class










class Date
//note capitals
{ public:
Date();
// constructor
Date(int int); // this gives the option of changing
// the Date
void add_day (void);
void display(void);
private:
int day;
//these are the so-called attributes
int month;
};
The Date class





Before we declare the class, we must decide what
we want to store in it and how we want to access
the data:
It should hold a pair of integers representing the
month and the day of the month
We want to be able to create an object and specify
the date it represents
We want to be able to increment the date by one
day
We want to be able to print the date.
The Date class

Firstly we declare the class by name, Date,
and then declare the interface
The public interface





The first thing we have to declare for any class is its
constructor.
Without a constructor there is no way to instantiate
(create) an object.
Normally an object has a so-called default
constructor, which creates a default instance of the
class and initialises its data.
In this case the declaration takes the form Date();
This is the block of code that will be called by code
such as Date today; the date represented by the
object it creates will be the default.
The Date class





Next we define a constructor that allows us to create
a Date object and specify the date it represents:
Date(int, int); This is the method called by code such
as today = Date(5, 3);
The add_day() method will be used to add one day
to the date.
It takes no arguments and returns nothing.
This function will change the data and is known as a
mutator.
The Date class





The last method declared, display(), also takes no
arguments and returns nothing.
It will be used to print the date.
Since the method does not modify but only
accesses data it is known as an accessor function.
We can add the keyword const to the declaration so
the compiler knows the function should not change
the data fields.
Not done here.
The Date class: The private
interface



Next we turn to the private part of the class
declaration.
Here we declare the data fields and methods
we want the class to encapsulate (hide).
We only have two data items, the day and the
month, both integers.
Defining the class's methods







We now have to define these functions.
Since the identifier of a member function may be used in
several classes we have to explicitly identify the class
whose member function we are defining. To do this, we
use the :: notation. We begin by defining the default
constructor.
Date::Date() //:: is the scope resolution operator
{
day = 1;
month = 1;
}
The class’s methods
Next we define the add_day function
void Date::add_day(void)
{ if (is it the last day of the month?)
{ day = 1;
month = month % 12 + 1; //increment
//the month
}
else day++;
}

The Date class



This code is incomplete because we have no way
yet of knowing which is the last day of the month.
We can therefore define a global, constant array of
13 integers, each element containing the number of
days of the appropriate month.
Since January is month 1, we can define the first
element of the array as zero.
The Date class



const int mdays[] = {0, 31, 28, 31, 30, 31, 30 ,
31, 31 , 30, 31, 30, 31};
Similarly we can define an array to hold the
names of the months:
const string mnames[] = {"", "Jan", "Feb",
"Mar", "Apr","May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"};
The Date class
We are now in a position to test for the last day of the
month and can amend the add_day() function as
 follows:
void Date::add_day(void)
{ if (day == mdays[month]) // is it last day of the
// month?
{ day = 1;
month = month %12 + 1;
}
else day++;
}

The Date class
The display() function is easily defined:
void Date::display(void) const
{
cout << day << " " << mnames[month] << endl;
}

The Date class



Finally we come to the second constructor function
that allows us to specify the date.
We have to test the validity of the arguments
supplied, which we can do either by including the
<cassert> library and an assert statement or by
writing some output to the cerr output stream and
calling the exit function
(requires the <cstdlib> library)
The Date class












Date::Date(int d, int m)
{ assert(m >= 1 && m <= 12 && d >= 1 && d <= mdays[m]);
// assert requires the <cassert> library
/* exit function as follows:
if(m<1 || m>12)
{ cout << "Invalid month." << endl;
exit(1);
}
*/
day = d;
month = m;
}
The Date class
All the declarations in the class have now been defined.
 We can create a main() function to test it:
int main(void)
{ Date d1;
Date d2(30, 11);
d1.display();
d2.display();
d1.add_day();
d1.display();
} //see Date.cpp

The Queue class
//this class implements a queue
class Queue{
int q[100];
int sloc, rloc; //start location and rear location
public:
void init();
void qput(int i);
int qget();
};

Classes continued

So a class contains both private and public
members



So q, sloc and rloc are private, this means that
they can be accessed only by other members of
the queue class e.g. the functions of this class
and NOT by other parts of the program in which
this class has been written.
The functions are also referred to as methods
This is known as ENCAPSULATION.
Classes continued


Typically we place the functions in the public
interface and the data in the private interface,
but we can declare private functions if we so
wished.
The functions init(), qput() and qget() are
called member functions of the class, note
the parentheses to denote that they are
functions.
Classes continued




Keep in mind that an object forms a bond between the functions
and the data.
A member function has access to the private parts of the class of
which it is a member.
Thus init(), qput() and qget() have access to q, sloc and rloc.
Once a class is declared we can create objects (variables) of the
type class as follows:
 Queue q1, q2

This will declare two objects q1 and q2 of type Queue
Declaration of classes
class class_name{
private: data and functions
public: public data and functions
} object_list;
//recall we can do this with structs i.e. the
//object list part
Coding the functions

void queue::qput(int i)
{
if (sloc==100){
cout << “Queue is full ” << endl;
return;
}
sloc++;
q[sloc] = i;
}
//this will put the value i at position q[sloc] in the //array
of integers
:: The scope resolution
operator



Note the use of the ::
This is known as the scope resolution operator,
which means that the function name to the right of
the two colons is in the scope of the class name to
the left of the colon
In short it means that the function (or method)
belongs to the class or the method is in the scope of
the class.
The :: operator again





The :: is called the scope resolution operator.
Essentially it tells the compiler that this version of
qput belongs to the queue class
Or put differently :: states that qput() is in Queue’s
scope
Member functions can only be invoked relative to an
object. To call a member function from part of your
program that is not part of the class one must use
the object name and the dot operator, as we did with
structs e.g.
Queue ob1,ob2;
ob1.init();
The dot operator continued



The invocation ob1.init() causes init() to
operate on ob1’s copy of the data.
Keep in mind that ob1 and ob2 are separate
objects.
Now look at queue.cpp and discuss
A closer look at class member
access



How to access class members is a cause of
considerable confusion for programmers.
So for this reason we will look at this in more
detail.
Look at myclass.cpp example and explain
Member function access
continued





Lets look at setab().
As is it a member function it can refer to a and b
directly without explicit reference to an object i.e.
without the dot operator
Second note that a is private and b is public, so b
can be accessed by code outside myclass. So
main assigns a value of 20 to b
reset() is a function of myclass so has access to
members of the class without the use of dot
operator.
In this case it calls setab()
Constructors and Destructors



It is very common for some part of an object to
require initialisation before it can be used.
Recall the queue class previously, before the queue
could be used the variables rloc and sloc were set to
zero. This was done using the function init().
Automatic initialisation is done using the
constructor

Lets look at the queue2.cpp. (no constructor)
The use of a Constructor





queue::queue() //note no return type
{
rloc=0;
sloc=0;
cout << "Queue initialised " << endl;
}

Here the constructor writes to the screen Queue initialised, this is not
common.
An objects constructor is called when the object is created
The Destructor



The complement to the constructor is the
destructor.
In many cases an object will need to perform
some action or series of actions when it is
destroyed
Reasons for destructor: object may need to
deallocate memory that it had previously
allocated
The Destructor


In C++ the destructor is the function that handles
deactivation. The destructor has the same name as
the constructor and thus the class, but it is preceded
by the tilda ~.
Like constructors they do not have a return type.
The queue class does not require a destructor but
we will include one for illustration, see queue3.cpp
Parameterised Constructors




A constructor function can have parameters thus we
can have different signatures for the constructor.
This allows you to give member variables values on
inception
Lets look at queue4.cpp
Here we will see a constructor with more than one
signature, this is known as POLYMORPHISM
analogous to OVERLOADING
Public and Private


If you look closely at the previous definition of our classes
you may note one or two things
class definition is similar to struct definition


In fact C++ treats structs as classes where by default all
members are public
class definition contains function prototypes


the operations are bound tightly to the data
class functions know about class data so you do not need to
pass class data to functions as arguments
The Private and public
interfaces



class definition has a line with a label public:
this tells the compiler which parts of the class
are visible to other things (clients) e.g. main()
class members are by default are private.
That is private members functions and data
are hidden to all.
private data and functions are only visible to
an object itself.
Class Data Manipulation

The principle of Information Hiding is the
key for Object Oriented Programming.
Access to data is tightly controlled via public
interface functions

“Setters” to set data members


SetHeight(3);
“Getters” to obtain values of data members
y = myTime.Write();
Here myTime is an object of type Time, say.

Built in operators

int, char, float, double have built in operators




+ * / % etc
classes do not have them
like structs they have . (dot) and =
You have to define and implement your own
operators

It is possible but perhaps beyond this course to redefine
the built in operators to work on YOUR class.
Specification an
Implementation
Like Abstract Data Types (ADT’s) there are two
parts to classes
1. the specification – where one declares the
class
2. implement the function definitions i.e. to
code the functions. This is not crucial but it
is how it is discussed in many text books.
Key Points so far

Shows practical elements of object oriented programming .

Information hiding


Via class syntax
Loose coupling

Classes are very self contained

There only interaction with other parts of a project is via its public
interface which can be strictly monitored

They are very independent to other parts of your program

They can therefore be developed and tested in isolation



They are ideal for team programming


They result in more robust code
They are easy to reuse/ adapt/extend/
For large project they are more productive
They are ideal for large programs
Constructors and Destructors




Constructors guarantee initialisation and are called
when an object is created
Usually we want to set up an object with certain
values for its data.
Special member function called a constructor will
“construct” or initialise any instance of our class
exactly how we want to.
The constructor is called at the time of object
instantiation! i.e. when we create an object of that
class.
Revised class declaration
class Time
{
public:
void setTime (int hours, int minutes, int seconds);
void print24hour();
void print12hour();
Time(int initHrs, int intMins, int initSecs)
//constructor
Time (); // overloaded constructor
~Time();
//destructor
private:
int hour;
int minute;
int second;
};
Define constructor
Time::Time()
{
cout << “Setting the time” << endl;
hrs=0;
mins=0;
secs = 0;
}
//Note the constructor has the same name as the class itself
//constructors have NO RETURN TYPE not even void.
Purpose of constructor and
destructor


They ensure that objects created are properly initialised
They ensure that they are properly destroyed


So they can sort out any garbage collection, for example
memory de-allocation.
Once this is done properly then class can be used
more reliably.
Summary
 A class can be used to implement an ADT







A class specifies members - the data and operations
(methods)
Information hiding is a central idea to classes
class members are private by default so if you forget to
include an interface they will be private by default
Interface functions are explicitly labelled as public
Classes provide automatic initialisation through constructors
Classes provide a place for garbage collection through
destructors.
Creation of an object is achieved via a declaration
statement.
Structures versus Classes






On the surface structures and classes are virtually identical,
so why introduce the class?
Answer is rooted in C. A C struct is valid in C++. C has no
concept of private or public all members are public in structs
In C++ members are private by default as we are trying to
achieve encapsulation
So to be compatible with C a new keyword was added.
A struct is a class.
Look at displaydatestruct.cpp
Arrays of objects

We can create arrays of objects just as we
had arrays of structs previously
Look at display.cpp
Pointers to Objects




As you know you can access a structure directly, or
through a pointer. In like fashion you can access an
object either directly or by using a pointer
Recall that a pointer stores an address
To access an element of an object when using the
actual object itself use the dot operator. When using
the pointer we use the -> (dereferencing operator)
See example p_Example.cpp
Extending classes





Here we derive one class from another
The derived class is called the child class or
the subclass
The class derived from is called the
superclass or the parent class
If one imagines set theory the parent class is
a sub set of the child class
Inheritance is known as a “is a” relationship
Extending in OO programming

Analogy to set theory
Child class
Parent class
enum ZoneType {EST, CST, MST,
PST, EDT, CDT,MDT}
class ExtTime:public Time
{
public:
void Set(int hours, int
minutes, int seconds);
void print24hour();
void print12hour();
ExtTime(int int Hours, int
initMins, int initSecs,
ZoneType initZone);
ExtTime();
private:
ZoneType zone;
};
instantiate object A of type
ExtTime
int main() {
ExtTime1 A;
return 0;
}
Further Ideas



C++ and other object oriented languages
take things further.
For example, Suppose we had a problem
modelling vehicles
We need an Abstract Data Type (ADT) for a
vehicle
Vehicle ADT
DATA:
Position
Speed
heading
Operation
Accelerate
Break
Turn
DisplayInfo
Suppose we want to model a
bus


A bus is a kind of vehicle
It would be good if we could make use of our
vehicle implementation and extend it to
include bus specific data members and
operations
Bus ADT
bus is a kind of vehicle plus
DATA:
nPassengers
Operations:
board passenger
alight passenger
DisplayInfo
This can be done using Inheritance


A class can inherit data and operations from
another class
It can also redefine operations (this is called
polymorphism) so that they work with the new
class

e.g DisplayInfo will need to be adapted to display bus
specific information as well as vehicle information.

This process of inheritance further extends the
programmers ability to reuse and extend code
already written.

These principles, lie at the heart of OOP
 Information hiding
 Inheritance and polymorphism
Object Oriented Programming




Identify what the goals are for a problem
Identifying the objects that make up a
problem
Identifying how the object in a problem
interact with each other in order to satisfy the
goals
Specifying ADTs that describe the objects
and operations needed for the problem
JAVA



The second module at Oxford in JAVA takes these
concepts further
JAVA is a “pure” object oriented language with a distinct
C++ flavoured Syntax
It is pure in the sense you cannot program in Java without
classes.