Home Page
The Basics
Arrays

Abstract Data Types
Dynamic Memory Allocation
Operator Overloading
Lists
C++ Style Strings
Linked Lists
Stacks and Queues
Variable Data Types
Templates
Sorting
Classes

Classes are similar to structs with the exception of a few things.

1)  classes can have member functions.
2)  they support public and private data

Example:

class myclass
{
private:              // by default all class members are private
     int x,y;
     char c;
     int func(void);
     Mytype acct;     // you can also have a member of another
                      // type that you created.
public:
     void setx(int x);
     myclass()        // default constructor to initialize
     ~myclass()       // destructor to clean up out of scope
};

in the main you can code the following:

#include <iostream>

int main()
{
myclass c;
c.setx(10);     // can do because member function is public
return 0;
}

You can't code c.x = 10; because x is a private variable.
…use get and set to retrieve and set values.

class Target
{
     int x,y;
     bool found;
};

Then in main to declare you would code…
Target p[3];     //declares an array of Targets

to get at the information you do similar to a struct:
p[2].x
p[2].y
p[2].found = true;
More Examples:

class T
{
public:
     int x,y;
     double f;

private:
     int j,k;
};

in main( )…

T a,b;     // variables - objects - instances of type T

a.y = b.x;     // OK
a.f = b.y;     // OK
a.f = b.j;     // Can't because j is private
a.j = b.j;     // Can't   "          "

**One helpful thing in C++ classes is that you can do direct assignment of class varialbes without worrying about copying each one.

i.e.   a = b;     // copies all elements of a into b

This is an easy way to copy arrays in one fall swoop.

Class Member Functions:
They only apply to the class that they are in.

any member function has access to all of the members of the class so when you are outside you can use a function to get a value when you cannot access the data members directly.  This is where a get and set function come into play.

Member Function Headers:
int T::get_j(void)
{
     return j;      // sends current instance of j
}

first you have int as a return type
T distinguishes the function as a member of class T
get_j is the method name

when you call this function you use a.get_j() and it will call the function and return the value of j for the instance a of the class T

void T::set_j(int I)
{
     if(I<0)     // lets you set positive values only
          return;
     j = I:
}

later on in the code you call…
a.set_j(3);     // lets you set private value of j to value of 3 because of design of class


Constructors:
You always use a constructor to initialize variables.  Even when you don't code it in, a default constructor is added. They always have the same name as class.

Example:
class M
{
     int x,y;

public:
     M();       // default constructor
     M(int)     // constructor for different purpose
};


M::M( )
{
     x = 7;     // can do anything inside
     y = 3;     // now everytime the program calls class M
}               // x will be set to 7 and y set to 3

When calling..
M t;            // x and y members of M are given 7 and 3 respectively.

M::M(int j)
{
     x = 7;
     y = j;
}

One thing to be aware of is if you, for instance, have x in function header…
M::M(int x)
{
     x = 7;
     y = x;
}

So now with two constructors, there are multiple ways to call the constructors.
M a;             // Calls default constructor
M b(5);          // Calls second constructor
M c=5;           // also calls second constructor

Sample Code:

#include <iostream>

class A
{
     int x;

public:
     A();          // constructor is always public
     A(int);

     int get_x(void);
     void increment(void);
};



Sample code continued:
A::A()
{
     x = 0;
}

A::A(int s)
{
     x = s;
}

int A::get_x(void)
{
     return x;
}

void A::increment(void)
{
     x++;
}

int main()
{
     A a;
     A b(5);

cout << a.get_x(x) << endl;
b.increment();
cout << b.get_x( ) << endl;
return (0);
}

Breaking Up A Program:
To make your code manageable you should break it up into several files and then link them together when you compile.  This will eliminate the problem of having to change something in the source code and then having to re-compile the entire project.  This seems like small potatoes now but when the projects take hours to compile you will understand the importance more.

From now on in this class, each class should have it's own .C and .h files which will be linked to source code.

Now in another file named A.C

#include "A.h"

A::A( )          // default constructor
{
     code to initialize
}

A::A(int x)      // initialize for special use
{
     special initialization
}

void A::print(arguments)
{
     printing code
}

same follows for B.C file for all B class member functions.

so now you will have
test.C
A.C
B.C
A.h
B.h

all together they make test.o, A.o, and B.o  which are linked to test, your executable
This can get rather sticky so use your Makefile to avoid errors…

CC = g++
CCFLAGS = -Wall -O

test : test.o A.o B.o
     $(CC) $(CCFLAGS) -o test\
        test.o A.o B.o -lm(if needed to link math)

test.o : test.C A.h B.h
     $(CC) $(CCFLAGS) -c test.C

A.o : A.C A.h
     $(CC) $(CCFLAGS) -c A.C

B.o : B.C B.h A.h
     $(CC) $(CCFLAGS) -c B.C

clean:
     -rm *.o test

note the \ in the first section… This is a way to extend the line in a Makefile.  In order to implement this, you have to put a <cr> directly following the \.

Reading Files:

if you want to access a binary data file from the command line prompt you would include the following:

#include <fstream>

ifstream myfile;

myfile.open("filename", ios::in|ios::binary);

then at the command prompt you would type:

     executable information.dat

when you write your main function it would look something like this…

int main(int argc, char * argv[ ])

argc returns the number of arguments(2) while argv[ ] returns information.dat in this case

to test if two arguments were entered you can code:
     if (argc != 2)
          cout << "Error please include data file" << endl;
     myfile.open(argv[1], ios::in|ios::binary)
     if (!myfile)
          cout << "Error opening file" << end;

Debugging:
make > errs     redirects output to filename
make >& errs     redirects std. output and std. errs

Segmentation Fault:
This most often happens when you are trying to write outside the bounds of an array or pointer that wasn't properly set.

Core dump:
When your program fails when running, all information about your program is placed in a core file.

cerr <<:
remember to use the old faithful standby of print statements to check where you are in code.

Gnuu:
This is the debugger we can use in this system.  To use it you must include the -g option in your makefile g++ lines.
     g++ -Wall -c -g test.C
     g++ -o test -g test.o
A good way to do this is to make it part of the CCFLAGS statement but you must ALWAYS remove the -g before submitting assignment for grading.

at prompt type gdb… Example:     mp% gdb assign4<cr>
the prompt will then change from mp% to (gdb)
gdb options:
r     -(or run)will run debugger
bt     -(backtrace) use u for up and d for down (gives list of all functions called in reverse order)
l     -(list) lists code in stack with line numbers where you currently are ("l" again gives you next 10)

to run line by line:
b 35     -(break) sets a break at line 25
n     -(or next) will step over and execute following line.  every <cr> will execute another line
s     -(or step) will step into a function
p     -(or print) ie. p n.targets will print value in variable n.targets
c     -(continue) after the break point
delete 1     -will delete breakpoint #1
quit     -will quit the debugger
you can even change values while running debugger.

Example:
print grid [0][3]<cr>           // prints out what's there
print grid [0][3] = `J'<cr>     // changes value of variable



Sample Code:
following is an example of the .h and .C files to make a class of complex numbers and to implement them in a source code.  This should help to make things clearer.


Complex Class:
in filename:     complex.h

#ifndef COMPLEX_H
#define COMPLEX_H

class complex
{
     double re, im;     // representing real and imaginary

public:
     complex();
     complex(double r);
     complex(double r, double i);

};
#endif     /*  COMPLEX_H  */

in filename:     complex.C

#include "complex.h"

complex::complex()
{
     re = im = 0.0;     // initialize all to 0
}

complex::complex(double r)
{
     im = 0.0;
     re = r;
}

complex::complex(double r, double i)
{
     re = r;
     im = i;
}
in filename:     test.C

#include <iostream>
#include "complex.h"
.
.
.
int main()
{
complex a;           // calls default constructor
complex b= -3.7;     // calls second constructor
complex c(2.5, 3.7)  // calls third constructor
.
.
.
return (0);
}

default arguments:
in C++ class definitions you can just write one constructor that will take the place of all three.
example:
     complex(double r=0.0, double i=0.0);

now you can call the same way…
complex a;          
complex b= -3.7;     
complex c(2.5, 3.7)

now all will call the same constructor using the default arguments given.     

recall:
in main code:
     get(char *p, int n);
     get(char *p, int n, char term);

in header for class:
     get(char *p, int n, char term = `\n');

this is an example of what we already do that uses default arguments.  If you specify a terminating character or if you don't it will work either way.

this:
this is a keyword in C++ which refers to the current instance

How do we use this?

complex a(1,1), b(2,-1);
complex c;

c = a + b;     // this would be nice…


Overloading operators:
in C++ you can overload operators as well.  In example, we can write code to add two things we have created..    in the class..

complex operator+ (complex b);
                  (const complex &)const; //const because constant instance

in a member method:
complex complex::operator+ (complex b);
{
     complex result;

     result.re = re + b.re;
     result.im = im + b.im;
     return result;
}

now you can just add the types together.

in regular function:

complex operator+ (const complex &a, const complex &b)
{
     complex result;

     result.re = a.re + b.re;     // must pass each value
     result.im = a.im + b.im;     // assuming they are public
     return result;
}
in member function:

void complex::print(void)
{
     cout << re << "  " << im;
}

overloading the << operator

ostream & operator << (ostream &ostr, const complex &c)
{
     ostr << c.re;
     ostr << "  ";
     ostr << c.im;
     return ostream;
}

inside our complex class… we have data members to public methods in public: that mention other functions.

friend:
friend says that here is a function that is not part of this class but is safe and allowed to access private parts of this class.  Friend is used only inside the class definition.

class complex     // revisited
{
public:
     friend ostream & operator <<(ostream &ostr, const complex &);
};
class declaration:
ie. class ostream;     can only be used when class is a reference.  For example…
ostream & operator << (ostream & ostr…)