Overview

STREAMS

The stream i/o class hierarchy is shown below

Stream I/O class hierarchy

Streambuff is the base class and all the derived classes have inherited its characteristics.

At the most basic level :

cin.get(letter);

... will take a letter from the input stream (probably the keyboard) and put it into the variable 'letter'. This has replaced the C getche() function.

There is no such function in C called getche() - ho hum....

cout.put(letter);

... will send letter to the output stream (probably the screen)

There is a simplified shorthand way of using these commands:

cin >> letter;

cout << letter;

cout << 5 + 5; // will calculate 5+5 then display the result

To read a whole line of text from the keyboard...

cin.getline(TextString,80,'\n');

... will read upto 80 characters or until enter is hit. The text will be stored in a string called TextString.


THE IOS CLASS

The ios class offers several extra features:

flags
rdstate
precision
setf
eof
clear
unsetf
fail
tie
width
good
fill
bad

Not sure why these are described as features - they're not!

The class istream offers these features:

get
peek
read
putback
getline
seekg
gcount
tellg

ostream offers

put
write
seekp
tellp

The ios class has format flags

flag			meaning
skipws			skip whitespace on input
left			left adjust on output
right			right adjust
internal		pad after sign or base indicator
dec			decimal
oct			octal
hex			hex
showbase		show integer base
showpoint		show decimal point & trailing zeros
uppercase		uppercase hex characters
showpos			+ before positive numbers
scientific		scientific notation
fixed			floating notation
unitbuf			flush o/p after each operation
stdio			flush o/p after char inserted


EXAMPLE

int number = 45;
cout.setf(ios::hex | ios::showbase | ios::uppercase);
cout << number << endl;

output

0X2D

(i.e. the value is in hex, base is shown, the hex characters are uppercase. The endl is a way of adding a newline to the end of a line)

endl while it will give a return - this is probably the glibbest description of what end does!

The output can be reset using the unsetf function:

cout.unsetf(ios::uppercase);

will no longer show hex characters in uppercase.

EXAMPLE

double pi = 3.141592654;
cout.width(12);
cout.precision(4);
cout.fill('!');
cout << pi << endl;

will look like this:

!!!!!!3.1415

MULTIPLE INHERITANCE

This is when a new class will inherit the characteristics of more than one existing class:

class c : public a, public b
{
  // new class declarations
};

New class 'c' has inherited both class 'a' and class 'b' characteristics.


VIRTUAL BASE CLASSES

Consider a class heirarchy where a base class 'A' is inherited by two classes 'B' and 'C'. A fourth class 'D' has the characteristics of both 'B' and 'C'

class a
{
  public:
    int x;
};

class b : public a
{
  public:
    int y;
};

class c : public a
{
  public:
    int z;
};

class d : public b, public c
{
  public:
    void PrintNums() { cout << x << " " << y <<" " << z << "\n"; }
};

void main()
{
  d d_ex;
  d_ex.x = 5;
  d_ex.y = 6;
  d_ex.z = 7;
  d_ex.PrintNums();
}

The above code will not work. The compiler can see two ways to get to variable d_ex.x


The problem is resolved by adding the keyword 'virtual' to the declarations of 'b' and 'c':

virtual is not a keyword - it's a modifier

class b : virtual public a
class c : virtual public a

EXPLANATION

The choice of which overoaded function to use is made at compile time. This is known as 'early binding'. Choice of virtual code is made at run time i.e. 'late binding'. In the above example, the user need not worry which class ('b' or 'c') the class 'a' is accessed through. Only one path will be taken. The unused class will not exist (since it is virtual) so no ambiguity exists.

Late binding is slower to execute than early binding.


POINTERS TO STRUCTURES

Way way back, many moons ago, we had K & R and it did us well for a long long time..., stdio.h was happy and main was an implicit int. Then things moved on... main *had* to return an int and in C++ land, the C headers could be safely used by adding "c" to before the header name and dropping the .h - not whoever wrote this had noticed....

It's worth noting as well that the practice of placing things on the stack is rather dangerous for beginners. new has been covered by now, so why not use it?

#include <stdio.h>

main()
{
  struct shopping
  /* define structure containing 2 integers */
  {
    int ItemOne;
    int ItemTwo;
  };

  struct shopping list[100], *MyPtr;
  /* list is an array of type shopping */
  /* MyPtr used to point to a type shopping */

  MyPtr = &list[34];	/* point to where list[34] is */
  MyPtr -> ItemOne = 16;	/* access ItemOne within list[34] */
  printf("%d\n",MyPtr->ItemOne);	/*print what MyPtr points to */
}

Summary:

struct shopping list[100],*MyPtr;

means the MyPtr points to an array, each box of which has a structure in it.

MyPtr = &list[34];

means MyPtr points at box 34

MyPtr->ItemOne = 16;

means point at ItemOne with the structure in box 34 and set ItemOne to be 16.


POINTERS TO CLASS HEIRARCHIES AND ASSOCIATED PROBLEMS

Pointers can be used to point to class memebers in the same way that structure members can be accessed:

#include <iostream.h>

class parent
{
  public:
    void print(void) { cout << "Parent function\n"; }
};

class son : public parent
{
  public:
    void print(void) { cout << "Son function\n"; }
};

class daughter : public parent
{
  public:
    void print(void) { cout << "Daughter function\n"; }
};

void main(void)
{
  parent p;		// p of type parent
  son s;		// s of type son
  daughter d;		// d of type daughter

  parent *pptr = &p;
  son *sptr = &s;
  daughter *dptr = &d;

  pptr->print();		// prints : Parent function
  sptr->print();		// prints : Son function
  dptr->print();		// prints : Daughter function

  pptr = &d;		// pptr now points a 'd'
  pptr->print();		// STILL prints : Parent function

  pptr = &s;		// pptr now points at 's'
  pptr->print();		// STILL prints : Parent function
}

This isn't a bad example - but it completely lacks any explaination as to why when pptr points at "s" or "d", it still outputs the "p" parent function


EXERCISE 19

Construct a class that amongst it's data members, contains a pointer to a simple variable. Declare an object of the class and a pointer that points to it. Use the -> indirect member selector operator to access the data members in the class.

SUMMARY

If a pointer is used to point to a base class object (e.g. pptr pointer pointing to parent), the other pointer remains pointing at the base class members and can only be used to access the base class members.

HOW TO OVERCOME THESE PROBLEMS AND POLYMORPHISM

This problem is overcome by defining the member function of the base class 'virtual':

virtual void print(void) { cout << "Parent function\n"; }

This way the pointer can be used to access the redefinition of the function in a derived class.

Instances of redefined functions do not need the virtual keyword. However it is still good practice to define them as virtual:

virtual void print(void) { cout << "Son function\n"; }

virtual void print(void) { cout << "Daughter function\n"; }

This means that virtual functions can be identified without reading the whole program.