You are on page 1of 53

Classes

Abhiram Ranade

Topics
l

The class concept

Simplecpp graphics shapes as classes

Building new graphics classes

A class for text data

Dynamic/Heap memory allocation

Classes
l

class = struct except


-

Members of a struct are public by default

Members of a class are private by default

class Complex{double r, i};


-

both r, i are private

struct Complex{double r, i};


-

both r, i are public

contd
struct Complex{
private:
double r, i;
public:
real_part(){ return r;}
imaginary_part{ return i;}
Complex(double r1, double i1){r=r1; i=i1;}
}
l

In this definition, all members are explicitly marked as


public or private. So this struct could be replaced by
class.

Why a new term?


l
l

struct of C: only data members. all public.


struct of C++: member functions also allowed.
private/public members allowed. public by
default.
To avoid having to say which struct you mean
(of C or of C++), better to use the term class.
But remember that in C++, class and struct are
slightly different.

Simplecpp graphics
l

Circle, Line, Rectangle, Text, Polygon are


classes.
You have been using classes/constructors all
along without knowing the names!

Circle c(30, 40, 5); // constructor call


c.setFill();
l

// member function call

Member functions not only create/modify the


variable, but also draw on screen. Look at the
code for the functions as given in simplecpp/
src.

Defining a new graphics component


l

It is customary to use buttons in graphics


programs:
-

Appearance: rectangle on the screen, with text


describing function.

If you click inside it, then some action happens.

Can you design a Button class which will make


it easy to put buttons on screen?

Specification
l

Define a button at a certain position, and of


certain size, with certain text in it.

Constructor:
Button(double cx, double cy, double w,
double h, char * textptr);
l

It should be easy to check if we have clicked


inside it.

Member function:
bool isInside(double clickx, double clicky);

Example of use
initCanvas();
Button b(100,100,100,50,Forward);
Turtle t;
while(true){
int cp = getClick();
if(b.isInside(cp/65536, cp%65536)) t.forward(5);
else if ...
}

Button class
class Button{
Rectangle r; Text t;
double cx, cy, width, height;
public:
Button(double x, double y, double w,
double h, char * textptr);
bool isInside(double clickx, double clicky);
} // member function bodies can be given //
outside

Constructor Body
Button::Button(double x, double y, double w,
double h, char *tptr){
cx = x;

// cx, cy ... from class definition

cy = y;
width = w;
height = h;
r.reset(cx,cy,w,h);
t.reset(cx,cy,tptr);
}

Note
l

l
l

When the constructor is called, an object of


type Button is first created.
Creating a button first requires constructing its
members.
So members r, and t are first constructed.
r is constructed by calling the default
(argumentless) constructor, equivalent to
writing Rectangle r;
Similarly Text t;

isInside
bool Button::isInside(int clx, int cly){
return (abs(cx - clx) <= width/2)
&& (abs(cy - cly)<= height/2);
}

Some other aspects of graphics


classes
int main(){
initCanvas();
{ Circle c(10,20,30);
...
} // what happens when control exits block?
...
}

Destructor Functions
l

l
l

When a struct object is to be destroyed, you


can say how the destruction is to happen by
specifying a destructor member function.
For graphics objects, the destructor function
will cause the object to be removed from the
screen.
Exact details later.
If you dont specify a destructor, a default donothing destructor is supplied by C++.

A remark
l
l

l
l

Old telephones: mode of operation is fixed.


New telephones: you can decide what ring
tone, what caller tune...
Old struct of C: behaviour is fixed.
New struct/Class of C++: you get to decide
what happens.

Passing graphics objects as


arguments to functions
Call by value: object copied. Should two pictures
appear on the screen? So not allowed.

Call by reference: Allowed.

void dance(Turtle &t){


for(int i=0; i<4; i++){
t.forward(10); wait(0.1); t.forward(-10);
t.left(90);
}
}
l

Call by passing a pointer: also acceptable.

Representing text data


Current representation: char name[50];
l

Allocate an array of maximum possible size.

Inefficient in general

Maximum possible size is hard to estimate

Operations on char arrays can be errorprone.

string: A C++ class for representing


text data
l

Can hold arbitrary length strings.

Efficient use of memory

Nice set of predefined operations

Already available as part of standard library of


C++. Excellent on-line documentation.
To use, include line:

#include <string>
l

How it is implemented? Later...

int main(){
string p=abc, q="defg";
string r=p+q; // concatenation
cout << p << "," << q << "," << r.length() <<endl;
p[2] = '1'; q[0] = p[0];
string t; getline(cin,t); // read line from keyboard
cout <<q.substr(2); // starting at index 2, to end.
string s = q.substr(1,2) // starting at 1, length 2.
int i = r.find("ab");

// find from the beginning

int j = r.find("ab",1);

// find from position 1.

} // returns string::npos if not found.

Exercise
l

Write a program that first reads a line from the


keyboard into a string object.
After that, it should create an array of 5 strings,
and extract the first 5 words (for fewer if there
arent 5) into the elements of the array.
After that the 5 words should be printed, one
word per line.

Solution idea
l
l

First consider how you would do it by hand.


Start at the beginning, and extract one word
after another.
To extract a word, look for a non-blank: that
gives the word start. Then look for a blank.
That gives the end of the word. Exceptions?
The word end of the ith word must form the
starting position to start for the word start of
the i+1th word.

string words[5], line;

getline(cin, line);

int current=0, wordcount;


for(wordcount=0; wordcount<5; wordcount++){
while(current < line.length() && line[current] == ' ') current++;
if(current == line.length()) break;
int nextblank = line.find(" ", current);
if(nextblank != string::npos)
words[wordcount] = line.substr(current,nextblank-current);
else{
words[wordcount] = line.substr(current); wordcount++;
break;
}
current = nextblank;
}
for(int i=0; i<wordcount; i++) cout << words[i] << endl;

How the string class is implented


l

Key question: how does a single variable


contain a string of arbitrary length?
Need to understand Memory model of C++.

Memory model of C++: 1


l

When a function executes, it is given an


activation frame.
When memory is demanded because of
variable definitions, it is given (automatically!)
from the activation frame.
When function finishes execution, the given
memory is (automatically) taken back.

Memory model of C++: 2


l

In addition there exists another block of


memory called Heap Memory
C++ programs can demand allocation from the
heap memory, by using the new operator.
The allocated memory can be returned by
using the delete operator.
Memory allocator keeps track of what
memory is available and what is free.
Details next.

Details
l

To allocate memory write:

ptr = new T; // ptr is of type T*


l

Heap memory allocator will reserve memory


for one T variable in the heap area.

Address of reserved region is placed in ptr.

Allocated memory can be used by writing *ptr.

To allocate an array, use:

ptr = new T[array_size]; // ptr is of type T*

Example
int main(){
int *ptr, *ptr2;
ptr = new int;
*ptr = 35;
ptr2 = new int[10];
for(int i=0; i<10; i++) ptr2[i] = i*i;
cout << *ptr <<' '<< ptr2[5] << endl;
delete ptr; delete[] ptr2;
}

Implementing a string class


We would like to
l

Declare variables to hold strings.

Initialize variables easily.

Print variables.

Concatenate strings.

Define arrays of strings

Example of main program


int main(){
String a,b; a = "pqr";

b = "stu";

String c = a + b;
b = a;
a.print(); b.print(); c.print();
String d[2]; d[0] = c + a;
d[0].print(); d[1].print();
}

d[1] = "xyz";

How to implement
l

Each variable of type String should only


contain a pointer to the actual string to be
stored.

struct String{ char *ptr; };


l

l
l

Universal Convention: pointer = 0 : indicates that


the pointer points to nothing. NULL
Can be used to indicate an empty string.

The actual string should reside in the heap.


In the heap, we will store '\0' terminated
strings.

What if two variables have the same


value?
Alternative 1: They point to the same region in
the heap.
more complicated record-keeping, discussed in
the book.

Alternative 2: Each variable points to distinct


region of memory.
Our choice here: Alternative 2. Because it is
simple.

Constructor
String(){ ptr = NULL; }
NULL is abbreviation for 0.
NULL is used to indicated that the pointer
does not point to anything meaningful
Use NULL instead of 0 for readability.

Assignment a = abc;
C++ considers this to be the same as a.f(rhs)
where f is a function operator=, and rhs is
abc. abc has type char*.
So all we need to do to support this is to
define member function with declaration:
void operator=(char *rhs);

Assignment a = abc;
void operator=(char *rhs){
ptr = new char [length(rhs)+1];
strcpy(ptr, rhs);
}
What if we write:
String a; a = abc; a = defg;

Assignment a = abc;
void operator=(char *rhs){
delete[] ptr; // OK even if ptr = NULL
ptr = new char [length(rhs)+1];
strcpy(ptr, rhs);
}

If ptr was originally pointing to some area of the heap, it is


returned back.

How do we know it is not needed by another variable?

Why dont we just write ptr = rhs?

Assignment a = b;
void operator=(String rhs){
delete[] ptr; // OK even if ptr = NULL
ptr = new char [length(rhs.ptr)+1];
strcpy(ptr, rhs.ptr);
}
Many operator= functions can be defined,
provided they take parameters of different
types.

Print member function


void print(){
if(ptr != NULL) cout << ptr << endl;
else cout << NULL << endl;
}

Concatenation: a + b;
Note that C++ considers a + b to be a.f(b)
where f is the function operator+
So we just need to define member function
operator+
This will return a String. So its declaration is:
String operator+(String b);

Concatenation a + b
String operator+(String b){
String res;
res.ptr = new char[length(ptr) + length(b.ptr)];
strcpy(res.ptr, ptr);
strcpy(res.ptr, b.ptr, length(ptr));
return res;
} // strcpy(x, y, m): copies into x[m], x[m+1]

What we have accomplished


Can define String variables. Initialized to NULL, or
empty strings to start with.
We can assign string literals, to String variables.
We can assign one String variable to another.
We can concatenate String variables into a new
String variable by using +.
Arrays can be defined.
We can print String variables.
User need not worry about new operator.

What we have not accomplished


If we define a variable inside a block, it will be
destroyed when we leave the block. So we
must remember to delete its memory. Ideally,
this should happen automatically.
There can be problems if we pass String
variables to functions in certain ways.
Cannot write cout >> variable etc.
See book for explanation and solutions (if
interested, not relevant for course).

The vector template class


vector: array++, i.e. more powerful version of
arrays.
The length can be increased during execution.
Algorithms available for sorting.
Available by including:
#include <vector>

Creating vectors
vector<int> v1; //zero length vector, int elements.
vector<char> v2(10); //length 10, char elements.
vector<int>v3(5,91); // length 5. each = 91.
vector<int>v4(v3); // copy of v3.

Working with vectors


cout << v.size(); //prints size (i.e. length) of v.
v4[3] = 22; //indexing allowed as usual.
v4.at(2) = v4.at(3); //indexing with bounds check.
// guaranteed error message if out of bounds
v.push_back(value);
// element appended, of given value.
v.pop_back(); // drop last element.

Sorting vectors
Need #include <algorithm>
vector<int> v(10);
for(int i=0; i<10; i++) cin >> v[i];
sort(v.begin(), v.end()); // sorts v!
v.begin(), v.end() : iterators. Say which
portion of v to sort. Discussed later.

Marks display variation 1.


int main(){
vector<double> marks;
double next;
while(cin >> next) marks.push_back(next);
sort(marks.begin(), marks.end());
for(int i=0; i<marks.size(); i++)
cout << marks[i] << endl;
}

Remarks
cin >> next : read value into next. But this is
an expression also.
Value of expression: cin if reading succeeds. 0
if reading fails i.e. False.
Reading can fail if file ends or any other
error, e.g. non-numeric input.
To signal end of file from keyboard, type ^d.

Marks display variation 2


struct Student{
int rollno;
double marks;
bool operator<(const student& rhs) const{
return rollno < rhs.rollno;
}
}

Defining operator< for Students


Will be used in sorting to decide which student
is smaller, i.e. should come earlier.
As defined: student with smaller roll number
will be < student with larger roll number.
const student& rhs: rhs operand has type
Student, and this member function will not
alter rhs operand.
const after parameter list: this function will not
alter Student on which function is called.
Both const keywords required.

Main program
int main(){
vector<Student> svec;
Student s;
while(cin >> s.rollno){
cin >> s.marks; svec.push_back(s); }
sort(svec.begin(), svec.end());
for(int i=0; i<svec.size(); i++) cout
}

Reading for vectors


Chapter 18.
Other parts of chapter 18 are useful for your
projects.
You might find it easier to use vectors instead
of arrays for projects.
Likewise matrix class from Section 13.4.
Neither vectors nor 13.4 included for Quiz 2.

Reading for string class


Section 18.2. Included for quiz 2.
Heap memory allocation and how to build
String class: not included for quiz 2.

You might also like