Download Pointers and Objects in C++: Lecture 5 and more Study notes Computational and Statistical Data Analysis in PDF only on Docsity!
Computing and Statistical Data Analysis
Lecture 5
Pointers
Strings
Introduction to classes and objects:
Declaring classes
A TwoVector class
Creating objects
Data members
Member functions
Constructors
Defining the member functions
Pointers to objects
Pointers
A pointer variable contains a memory address. It ‘points’ to a
location in memory. To declare a pointer, use a star, e.g.,
int* iPtr; double * xPtr; char *c; float *x, *y;
Note some freedom in where to put the star. I prefer the first
notation as it emphasizes that iPtr is of type “pointer to int”.
(But in int* iPtr, jPtr; only iPtr is a pointer--need 2 stars.)
Name of pointer variable can be any valid identifier, but often
useful to choose name to show it’s a pointer (suffix Ptr, etc.).
Initializing pointers
A statement like
int* iPtr;
declares a pointer variable, but does not initialize it. It will be
pointing to some “random” location in memory. We need
to set its value so that it points to a location we’re interested in,
e.g., where we have stored a variable:
iPtr = &i;
(just as ordinary variables must be initialized before use).
Dereferencing pointers: the * operator
Similarly we can use a pointer to access the value of the variable
stored at that memory location. E.g. suppose iPtr = &i; then
int iCopy = *iPtr; // now iCopy equals i
This is called ‘dereferencing’ the pointer. The * operator means
“value stored in memory location being pointed to”.
If we set a pointer equal to zero (or NULL) it points to nothing.
(The address zero is reserved for null pointers.)
If we try to dereference a null pointer we get an error.
Passing pointers as arguments
When a pointer is passed as an argument, it divulges an address to
the called function, so the function can change the value stored at
that address:
void passPointer(int* iPtr){ *iPtr += 2; // note iPtr on left! } ... int i = 3; int iPtr = &i; passPointer(iPtr); cout << "i = " << i << endl; // prints i = 5 passPointer(&i); // equivalent to above cout << "i = " << i << endl; // prints i = 7
End result same as pass-by-reference, syntax different. (Usually
pass by reference is the preferred technique.)
Pointers vs. reference variables
A reference variable behaves like an alias for a regular variable.
To declare, place & after the type:
Passing a reference variable to a function is the same as
passing a normal variable by reference.
passReference(j); cout << "i = " << i << endl; // prints i = 9 int i = 3; int& j = i; // j is a reference variable j = 7; cout << "i = " << i << endl; // prints i = 7 void passReference(int& i){ i += 2; }
Strings (the old way)
A string is a sequence of characters. In C and in earlier versions of
C++, this was implemented with an array of variables of type char,
ending with the character \0 (counts as a single ‘null’ character):
char aString[] = "hello"; // inserts \0 at end
The cstring library ( #include ) provides functions
to copy strings, concatenate them, find substrings, etc. E.g.
char* strcpy(char* target, const char* source);
takes as input a string source and sets the value of a string target,
equal to it. Note source is passed as const -- it can’t be changed.
You will see plenty of code with old “C-style” strings, but there is
now a better way: the string class (more on this later).
Example with strcpy
#include #include using namespace std; int main(){ char string1[] = "hello"; char string2[50]; strcpy(string2, string1); cout << "string2: " << string2 << endl; return 0; }
No need to count elements when initializing string with " ".
Also \0 is automatically inserted as last character.
Program will print: string2 = hello
A simple class: TwoVector
We might define a class to represent a two-dimensional vector:
class TwoVector { public: TwoVector(); TwoVector(double x, double y); double x(); double y(); double r(); double theta(); void setX(double x); void setY(double y); void setR(double r); void setTheta(double theta); private: double m_x; double m_y; };
Class header files
The header file must be included ( #include "MyClassName.h" )
in other files where the class will be used.
To avoid multiple declarations, use the same trick we saw before
with function prototypes, e.g., in TwoVector.h :
#ifndef TWOVECTOR_H #define TWOVECTOR_H class TwoVector { public: ... private: ... }; #endif
Data members of a TwoVector object
The data members of a TwoVector are:
private: double m_x; double m_y;
Their values define the “state” of the object.
Because here they are declared private, a TwoVector object’s
values of m_x and m_y cannot be accessed directly, but only from
within the class’s member functions (more later).
The optional prefixes m_ indicate that these are data members.
Some authors use e.g. a trailing underscore. (Any valid identifier
is allowed.)
The constructors of a TwoVector
The first two member functions of the TwoVector class are:
public: TwoVector(); TwoVector(double x, double y);
These are special functions called constructors.
A constructor always has the same name as that of the class.
It is a function that is called when an object is created.
A constructor has no return type.
There can be in general different constructors with different
signatures (type and number of arguments).
Defining the constructors of a TwoVector
In the file that defines the member functions, e.g., TwoVector.cc,
we precede each function name with the class name and :: (the
scope resolution operator). For our two constructors we have:
TwoVector::TwoVector() { m_x = 0; m_y = 0; } TwoVector::TwoVector(double x, double y) { m_x = x; m_y = y; }
The constructor serves to initialize the object.
If we already have a TwoVector v and we say
TwoVector w = v;
this calls a “copy constructor” (automatically provided).
The member functions of TwoVector
We call an object’s member functions with the “dot” notation:
TwoVector v(1.5, 3.7); // creates an object v double vX = v.x(); cout << "vX = " << vX << endl; // prints vX = 1. ...
If the class had public data members, e.g., these would also be
called with a dot. E.g. if m_x and m_y were public, we could say
double vX = v.m_x;
We usually keep the data members private, and only allow the user
of an object to access the data through the public member functions.
This is sometimes called “data hiding”.
If, e.g., we were to change the internal representation to polar
coordinates, we would need to rewrite the functions x(), etc., but
the user of the class wouldn’t see any change.