CSC 076

Programming in C++

Summary of 3/26 Lecture

Review of Sort Template Assignment

We began by discussing the HW #3a assignment.

//File:    sort.cpp
#include <fstream>
#include <vector>

void read_in (ifstream & in, vector<int> & v);
void sort (vector<int> & v);
void write_out (ofstream & out, const vector<int> & v);
using namespace std;

int main()
{
    vector<int> v;

    ifstream fin ("integers.txt");
    ofstream fout ("out.txt");

    read_in (fin, v);
   
    for (int j=0; j<v.size(); j++)
            cout << v[j] << endl;
    cout << endl;

    sort (v);

    for (int k=0; k<v.size(); k++)
            cout << v[k] << endl;

    write_out (fout, v);

    return 0;
}

//Since vectors are NOT automatically passed by reference
//the & is necessary (& v)
void read_in (ifstream & in, vector<int> & v)
{
    int number;
    int n=0;    //LOCAL VARIABLE NOW
    while (in>>number)
    {
        v.resize(++n);    //Vectors allow dynamic sizing of the list!
        v[n-1]=number;
    }
}

void swap (int & a, int & b)
{
    int temp;

    temp = a;
    a    = b;
    b    = temp;
}

void sort (vector<int> & v)
{
    for (int i=v.size(); i>=2; i--) // n = the number of items in the list
            for (int j=0; j<i-1; j++)
                    if (v[j] > v[j+1])
                            swap (v[j], v[j+1]);
}

void write_out (ofstream & out, const vector<int> & v)
{
    for (int k=0; k<v.size(); k++)
    {
        out << v[k] << endl;
    }
}

Essentially, assignment #3b is an extension to homework #3a.

//File:    sortVector.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

template<class T> void read_in (istream & in, vector<T> & v);
template<class T> void write_out (ostream & out, const vector<T> & v);
template<class T> void my_swap (T & a, T & b);
template<class T> void sort (vector<T> & v);

int main()
{
    vector<string>     s;
    vector<int>           i;
   
    cout << "What type do you wish to sort? (S) strings (I) integers ";
    char reply;
    cin >> reply;
   
    ofstream fout ("out.txt");
   
    cout << "What is the name of your input file? " << endl;
    string filename;
    cin >> filename;
    ifstream fin (filename.c_str());
   
   switch (reply)
    {
        case 'S':
        case 's':     read_in (fin, s);
                        sort (s);
                        write_out (fout, s);
                        break;
        case 'I':
        case 'i':      read_in (fin, i);
                        sort (i);
                        write_out (fout, i);
                        break;
        default:     cout << "Must choose either (S) or (I) " << endl;
    }
    return 0;
}

template<class T> void read_in (istream & in, vector<T> & v)
{
    T item;
    int n=0;
    while (in>>item)
    {
        v.resize(++n);    //Vectors allow dynamic sizing of the list!
        v[n-1]=item;
    }
}

template<class T> void write_out (ostream & out, const vector<T> & v)
{
    for (int k=0; k<v.size(); k++)
    {
        out << v[k] << endl;
    }
    out << endl;
}

template<class T> void my_swap (T & a, T & b)
{
        T temp = a;
        a = b;
        b = temp;
}

template<class T> void sort (vector<T> & v)
    {
        for (int i = v.size()-1; i>0; i--)
            for (int j=0; j<i; j++)
            {
                if (v[j] > v[j+1])
                {
                    //swaps v[j] and v[j+1]
                    my_swap (v[j], v[j+1]);
                }
            }
    }

NOTE:  When running on Visual C++ 6.0, four warning messages are issued.  Two of these originate in the vector class itself, while the other two are generated in the main() program.  Microsoft pragma's allow these messages to be disabled.  All of the implementations using vectors display the following preprocessing directive:

#pragma warning(disable: 4786)      // identifier was truncated to '255' characters in the debug information

I've include the help file on pragma's if you want to know more about them.

Iterators

Then, we introduced the notion of iterator.  Iterators are common in the ANSI C++ standards.  They are pointers that are roughly equivalent to the integer indexes of arrays.  That is, they allow advancement through a sequential structure without depending upon indexing.  The following is a partial implementation of the homework assignment using class iterators.

//File:    sortIter.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

template<class T> void read_in (istream & in, vector<T> & v);
template<class T> void write_out (ostream & out, const vector<T> & v);
template<class T> void my_swap (T & a, T & b);
template<class T> void sort (vector<T> & v);

int main()
{
    vector<string>     s;
    vector<int>           i;
   
    cout << "What type do you wish to sort? (S) strings (I) integers ";
    char reply;
    cin >> reply;
   
    ofstream fout ("out.txt");
   
    cout << "What is the name of your input file? " << endl;
    string filename;
    cin >> filename;
    ifstream fin (filename.c_str());
   
   switch (reply)
    {
        case 'S':
        case 's':     read_in (fin, s);
                        sort (s);
                        write_out (fout, s);
                        break;
        case 'I':
        case 'i':      read_in (fin, i);
                        sort (i);
                        write_out (fout, i);
                        break;
        default:     cout << "Must choose either (S) or (I) " << endl;
    }
    return 0;
}

template<class T> void read_in (istream & in, vector<T> & v)
{
    T item;
    while (in>>item)
        v.push_back(item);
}

template<class T> void write_out (ostream & out, const vector<T> & v)
{
    vector<T>::const_iterator    iter;
    for (iter=v.begin(); iter != v.end(); ++iter)
            out << *iter << endl;
    out << endl;
}

template<class T> void my_swap (T & a, T & b)
{
        T temp = a;
        a = b;
        b = temp;
}

template<class T> void sort (vector<T> & v)
{
    //What Goes Here???????   
}


Lab Exercise.  Complete the sort function using only iterators.  Feel free to use the files integers.txt and strings.txt to test your implementation.  If you run out of patience, you can check my version.


 

More on Overloaded Operators

An alternative to the previous version of the circle class in which the I/O operators were overloaded as auxiliary functions is provided through the use of so-called "friend" functions.  These are functions that are NOT part of the class, but are allowed access to the private data fields.  The following revised version of the circle class illustrates.

//File:    circle.h
#ifndef CIRCLE_H
#define CIRCLE_H

#include <string>
#include <iostream>
using namespace std;
class circle
{
    friend    ostream & operator << (ostream & out, const circle & c);
    friend    istream & operator >> (istream & in, circle & c);

    private:
        double m_rad;
        double m_x, m_y;
        string m_name;

    public:
        //Constructors
        circle ();
        circle (double xcoord, double ycoord, double radius, string name);

        //Destructor
        ~circle ();

        //Accessors
        double circumference () const;
        double radius () const;
        string name () const;
        void center (double & x, double & y) const;
};

#endif

The implementation can then take advantage of access to the private fields.

//File:    circle.cpp IMPLEMENTATION file
#include <string>
#include "circle.h"
using namespace std;

const double PI = 3.14159;

//Uses member initializer list
circle::circle () : m_rad(0.0), m_x(0.0), m_y(0.0), m_name("Unit Circle")
{
}

circle::circle (double xcoord, double ycoord, double radius, string name)
{
    m_x = xcoord;
    m_y = ycoord;
    m_rad = radius;
    m_name = name;
}

circle::~circle ()
{
}

double circle::circumference () const
{
    return (m_rad * 2.0 * PI);
}

double circle::radius () const
{
    return m_rad;
}

string circle::name () const
{
    return m_name;
}

void circle::center (double & x, double & y) const
{
    x = m_x;
    y = m_y;
}

ostream & operator << (ostream & out, const circle & c)
{
    out << c.m_name << " is located at (" << c.m_x << ", " << c.m_y << ")" << endl;
    out << "Its radius is: " << c.m_rad << endl;
    out << "Its circumference is: " << c.circumference() << endl;
    out << endl;

    return out;
}

istream & operator >> (istream & in, circle & c)
{
    in >> c.m_name >> c.m_x >> c.m_y >> c.m_rad;

    return in;
}

The driver program might look as follows:

//File:    circle_driver.cpp
#include "circle.h"
#include <fstream>
using namespace std;
int main()
{
      circle c, d(1.0, 3.0, 5.0, "Test Circle");

      cout     << "circle c; PRODUCED:\n" << c
                 << "circle d(1.0, 3.0, 5.0, ""Test Circle""); PRODUCED:\n"
                 << d;

        //The following makes use of the "copy" constructor
        //provided by the compiler
        circle e(d); //copies circle d into circle e
        cout << "circle e(d); THE COPY CONSTRUCTOR PRODUCED:\n" << e;

        ifstream fin("circle.txt");
        fin >> c;
        cout  << "ifstream fin(""circle.txt"");\n"
                << "with circle.txt: Joe 3 8 3\n"
                << "PRODUCED:\n" << c << endl;

        cout << "Name center(x y) radius " << endl;
        cin >> d;
        cout << d << endl;

        return 0;
}

Using the text file "circle.txt" as follows:

Joe    3    8    3

We get the following output:

circle c; PRODUCED:
Unit Circle is located at (0, 0)
Its radius is: 0
Its circumference is: 0

circle d(1.0, 3.0, 5.0, Test Circle); PRODUCED:
Test Circle is located at (1, 3)
Its radius is: 5
Its circumference is: 31.4159

circle e(d); THE COPY CONSTRUCTOR PRODUCED:
Test Circle is located at (1, 3)
Its radius is: 5
Its circumference is: 31.4159

ifstream fin(circle.txt);
with circle.txt: Joe 3 8 3
PRODUCED:
Joe is located at (3, 8)
Its radius is: 3
Its circumference is: 18.8495


Name center(x y) radius
mary 3 4 5
mary is located at (3, 4)
Its radius is: 5
Its circumference is: 31.4159

Unfortunately, because of a bug in Visual C++ 6.0, the "friend" access modifier doesn't work with the new C++ standard.  You must NOT invoke the "using namespace std".  Hence, the code must be rewritten using only .h headers and C strings (i.e., char*).  This version can be found in

More on the Visual C++ 6.0 bug can be found at

FIX 'using namespace std' Before Friend Operator Fails Compile


Lab Exercise.  Write a fraction class that incorporates the four operations add(), subtract(), multiply(), and divide().  Add accessor functions getNumerator() and getDenominator().  Use the testFraction driver program to test your work.

Add overloaded "friend" I/O operators << and >>.  Change the testFraction driver program accordingly.

Try your hand at overloading the "+" operator.


Back to C++ Home Page