We were given a task to use lists and iterators. We were supposed to make them from scratch. I'm done with that. The problems that I'm having are as following:

  1. I'm not able to access the list made of Course datatype which is present in each Student instance. Does this mean I need to make an iterator for that course list inside the student class?

  2. Similarly since I don't have direct access to The course list so I added the course into the Student list through the student objects not through the iterator. How can I do it through the iterator?

  3. Printing of a particular student and his courses is not happening as my iterator made for student only prints out the students, not the courses present in their courselist. How to do that?

Here's the code:

#include <iostream>
#include <string>
using namespace std;

const int ILLEGAL_SIZE = 1;
const int OUT_OF_MEMORY = 2;
const int NO_SPACE = 3;
const int ILLEGAL_INDEX = 4;
const int ILLEGAL_REFERNCE = 5;
const int COURSE_LIMIT_REACHED = 6;

template <class T>
class ListIterator;

template <class T>
class OrderedList {


    friend class ListIterator<T>;

private:

    int maxSize;
    int currentSize;
    T *listArray;
    bool removeAt(int index) {  

        if(index < 0 || index >= currentSize) throw ILLEGAL_INDEX;

        else {

            for(int i=index;i<currentSize;i++) 

                listArray[i] = listArray[i+1];

            currentSize--;
            return true;
        }                   
    }

public:

    OrderedList(int size);
    OrderedList(const OrderedList& copy);
    ~OrderedList();
    void setData(T s);
    T getData(int i);
    int getCurrent() { return currentSize; }
    bool isFull();
    bool isEmpty();
    int isPresent(T value);
    void insert(T value);
    bool remove(T value);
    int search(T value);
    void printData();
    const OrderedList& operator = (const OrderedList& assignment);

};

template <class T>
OrderedList<T>::OrderedList(int size) {

    if(size < 0) throw ILLEGAL_SIZE;

    maxSize = size;

    listArray = new T[maxSize];

    if(listArray == NULL) throw OUT_OF_MEMORY;

    currentSize = 0;

}

template <class T>
OrderedList<T>::OrderedList(const OrderedList& copy) {

    maxSize = copy.maxSize;
    currentSize = copy.currentSize;

    listArray = new T[maxSize];
    for(int i=0;i<currentSize;i++) {

        listArray[i] = copy.listArray[i];

    }
}

template <class T>
const OrderedList<T>& OrderedList<T>::operator= (const OrderedList& assignment) {

    if(this != &assignment) {

        currentSize = assignment.currentSize;
        delete [] listArray;
        listArray = new T[maxSize];

        for(int i=0;i<currentSize;i++) {

            listArray[i] = assignment.listArray[i];

        }
    }

    return *this;
}

template <class T>
OrderedList<T>::~OrderedList() {

    delete [] listArray;

}

template <class T>
void OrderedList<T>::setData(T s) {


        listArray[currentSize] = s ;

        currentSize++; 
}

template <class T>
T OrderedList<T>::getData(int i) {

    return listArray[i];        
}

template <class T>
bool OrderedList<T>::isEmpty() {

    return (currentSize == 0);

}

template <class T>
bool OrderedList<T>::isFull() {

    return (currentSize == maxSize);

}

template <class T>
int OrderedList<T>::isPresent(T value) {

    return(search(value));

}

template <class T>
int OrderedList<T>::search(T value) {

int low = 0;
int mid;
int high = currentSize-1;

    while(low<=high) {

        mid = (low + high)/2;

        if(value == listArray[mid])

            return mid;

        else if(value > listArray[mid])

            low = mid + 1;

        else
            high = mid - 1;
    }   
    return -1;
}

template <class T>
void OrderedList<T>::insert(T value) {


    if(isFull()) throw NO_SPACE;

    else {
    int i = currentSize;
    while(  i > 0 && value < listArray[i-1]) {

        listArray[i] = listArray[i-1];
        i--;
    }

    listArray[i] = value;
    currentSize++;
    }

}


template <class T>
bool OrderedList<T>::remove(T value) {

    int index = search(value);

    if(index == -1) return false;

    else {

        return removeAt(index);
    }
}

template <class T>
void OrderedList<T>::printData() {


    for(int i=0;i<currentSize;i++) {

        cout << listArray[i] << endl;

    }
}


class Course {

private:

    string ID;
    double GPA;

public:

    Course(): ID(""),GPA(0) {}
    Course(string id,double gpa): ID(id),GPA(gpa) {}
    double getGPA() { return GPA; }
    void printCourse() { cout << "Course ID: " << ID << " " << "GPA: " << GPA << endl;  }
    friend ostream& operator<< (ostream & out, const Course& course) { out << course.ID << " " << course.GPA << endl; return out; }
    bool operator< (Course c) { if (ID < c.ID) return true; else return false; }
    bool operator> (Course c) { if (ID > c.ID) return true; else return false; }
    bool operator== (Course c) { if (ID == c.ID) return true; else return false; }
};


class Student {

private:    

    string name;
    int rNo;
    int noOfCourses;
    double CGPA;
    OrderedList<Course> courseList;


public:

    Student(): name(),rNo(0),CGPA(0),noOfCourses(0),courseList(50) {}
    Student(string n,int r): name(n),rNo(r),CGPA(0),noOfCourses(0),courseList(50) {}
    void printStudent() { cout << "Name : " << name << " " << "Roll No: " << rNo << " " << "CGPA: " << CGPA << endl; if(noOfCourses !=0)  printCourse(); }

    int getRoll() { return rNo; }

    void addCourse(Course c) {

        if(noOfCourses < 50) {
        courseList.insert(c);
        noOfCourses++;
        }
        else throw COURSE_LIMIT_REACHED; 
    }

    void removeCourse(Course c) {

        if(noOfCourses != 0){
        courseList.remove(c);
        noOfCourses--;
        }

        else cout << "There are no Courses to be removed\n" << endl;
    }

    void printCourse() { cout << "Courses Taken\n\n"; courseList.printData(); }

    double calCGPA() {

        Course c;
        double sum = 0;
        for(int i=0;i<noOfCourses;i++){

        c = courseList.getData(i);
        sum = sum + c.getGPA();

        }
        CGPA = sum/noOfCourses;
        return CGPA;
    }


    friend ostream& operator<< (ostream& out, const Student& student) { out << student.name << " " << student.rNo << endl; return out; }
    bool operator <(Student s) { if (rNo < s.rNo) return true; else return false; }
    bool operator >(Student s) { if ( rNo > s.rNo) return true; else return false; }
    bool operator ==(Student s) { return (rNo == s.rNo); }

};

template <class T>
class ListIterator {

private:

    OrderedList<T> &list;
    int current;
    ListIterator & operator =(const ListIterator & rhs);

public:

    ListIterator(OrderedList<T> &l): list(l), current(0) { }
    ListIterator(const ListIterator<T> &li): list(li.list), current(li.current) { }
    void begin(){ current = 0; }
    int getCurrent() { return current; }
    void end() { current = list.currentSize; }
    bool isStart() { return current == 0; }
    bool isDone() { return current == list.currentSize; }
    void next() {

        if (!isDone()) current++;
        else throw ILLEGAL_REFERNCE;
}
    bool find(const T key) {

    current = list.search(key);

    if (current > -1) return true; 

    else return false;
}

    T getData() { return (list.listArray[current]); } 
    void setData(const T value) { list.listArray[current];  } 
    void insertData(T value) { list.insert(value); }
    void removeData(T value) { list.remove(value); }
    void getCourse(Student s) { getCourse(s); }
    void printData() { list.printData(); }

};



int main() {

/************************************
1. Creating An Empty List Of Students
************************************* */
    OrderedList<Student> studentList(10);

    Student s1("Hamza",12105092);
    Student s2("Ahmad",12105081);
    Student s3("Sherlock",12105032);
    Student s4("Watson",12134989);
    Student s5("Gary",12105042);
    Student s6("Ali",3111111);

/*****************************
2. Adding Students To The List
****************************** */

    ListIterator<Student> studentIterator(studentList);

    studentIterator.insertData(s1);
    studentIterator.insertData(s2);
    studentIterator.insertData(s3);
    studentIterator.insertData(s4);
    studentIterator.insertData(s5);

    studentIterator.printData();
    cout << endl;


/**********************************
3. Deleting A Student From The List
*********************************** */
    studentIterator.removeData(s1);

    cout << "List After Removing A Student\n" << endl;

    studentIterator.printData();

    cout << endl;

/*************************************
4. Adding A Course For A Given Student
************************************** */

    Course c1("CS102",3.44);
    Course c2("CS101",3.11);
    Course c3("MATH101",4);


    s5.addCourse(c1);
    s5.addCourse(c2);
    s5.addCourse(c3);

    studentIterator.setData(s5);


/*************************************
5. Remove A Course For A Given Student
************************************** */

    s5.removeCourse(c2);

    cout << "After removing a course\n" << endl;
    s5.printStudent();

/****************************************************************
6. Finding If A Student is Present Or Not Through His Roll Number
***************************************************************** */

    bool store; 
    string name;
    int rollNo;
    cout << "Enter The Student's Name and Roll Number To Find If He's Present In The List\n";
    cin >> name;
    cin >> rollNo;
    Student s7(name,rollNo);
    store = studentIterator.find(s7);

    if(!store) cout << "Student is not present in the list\n" << endl;
    else cout << "Student is present\n" << endl;


/*************************************************
7. Calculating CGPA For A Given Student's Roll No.
************************************************** */

    s5.calCGPA();
    s5.printStudent();

/***********************************************************************************************************************
8. Given The Roll Number, List All The Course A Student Has Taken Along With The Awarded Grades And GPA For Each Course.
************************************************************************************************************************ */

      int index = 0;
      cout << endl;
      cout <<"Enter the Student's name and Roll No. Whose Course Details You Want To Know" << endl;
      cin >> name;
      cin >> rollNo;
      Student s9(name,rollNo);
     store = studentIterator.find(s9);
     if(store) 
     cout << studentIterator.getData();

     else
         cout <<"Entered Roll Number Isn't Present In The List" << endl;


/*********************************************************************
9.  List all the students. (complete details – student and his grades)
********************************************************************** */

    studentList.printData();


return 0;

}

Ok there is lots and lots of little problems with this code.

But before I talk about some of them, I don't understand your use of the word iterator. In C++, the standard template library provides iterators to most container classes. In your instance you are providing a container class (OrderdList) and I would have expected your iterator to behave similarly to the existing iterators, i.e. as something that accesses members of the container in an order and without repeat.

In your case you have added ListIterator as a friend [high probability of poor design] and it does none of those things, but acts as a kind of "extra functionallity" namespace, that provides the equivilent of algorithms.

So for example: you write

OrderedList<Student> studentList(10);
Student s1("Hamza",12105092);
ListIterator<Student> studentIterator(studentList);
studentIterator.insertData(s1);

When something like, this would be expected:

OrderedList<Student> studentList(10);
studentList.push(Student("Hamaz",12105092);
//...
ListIterator<Student> IT;
for(IT=studentList.begin();IT!=studentList.end();IT++)
   std::cout<<"Student == "<<*IT<<std::endl;

Nothing intrisically wrong, in doing what you are doing, but it is unconvensional, probabily not what is asked for, and going to cause real confusion if you show it to someone else.

---------------

That said: What else is wrong with your code

(i) drop the constant on the assignment operator, and use this form:
OrderedList& operator= (const OrderedList&);

(ii) Care with array boundaries: Eg Image an ordered list of 10 items and 10 max size, in the method removeAt:

      bool removeAt(int index) {  

        if(index < 0 || index >= currentSize) 
          throw ILLEGAL_INDEX;
        else 
          {
            for(int i=index;i<currentSize;i++) 
          // i+1 is currentSize which is too big.
            listArray[i] = listArray[i+1];
            currentSize--;
            return true;
          }                   
      }

Why does the code need the else statement , surely you can't continue after the throw , and why return ture, whatelse will you return?,

(iii) The assignment operator,

    template <class T>
    OrderedList<T>& 
    OrderedList<T>::operator= (const OrderedList& assignment) 
    {

      if(this != &assignment) 
        {
          currentSize = assignment.currentSize;
          delete [] listArray;
          listArray = new T[maxSize];

          for(int i=0;i<currentSize;i++) 
            listArray[i] = assignment.listArray[i];
        }

        return *this;
    }

What hammens if maxSize is smaller than the current size of the OrderedList begin copied. opps -- memory corruptions.

(iv) setData -- no check to see if currentSize exceeds maxSize.

(v) search -- what happens if the orderedlist has no elements

(vi) conside this :

        Student():name(),rNo(0),CGPA(0),
           noOfCourses(0),courseList(50) {}

        void addCourse(Course c) 
           {
            if(noOfCourses < 50) 
              {
                courseList.insert(c);
                noOfCourses++;
              }
            else throw COURSE_LIMIT_REACHED; 
           }

I really don't like this : the problem with it is that you use a maxSize OrderList (of 50) and then separately test it in this function. NO!!! It is a bug waiting to happen. When you decide to
change the size of the courseList from 50 to 100. You have to do it in TWO places, and you will forget. If OrderList has a maxSize use it. If you try to insert more than the maxSize, then the insert method throws. Since you don't catch anything here, then it will not complete this function but exit, so you don't need two tests.

Throughout the code, you can use const (both method const and value const) and references e.g. I expect search to have this form

template <class T>
    int OrderedList<T>::search(const T& value) const 
**Finally the answer to your questions **--:

The answers to your question actual lie in re-writing iterator under the understanding that your class OrderedList could provide to methods
begin() and end() and that you will write an iterator class that accesses the OrderedList elements e.g. (in part)

template<typename T>
class OLIterator
{
  // stuff...
  public:

     OLIterator<T>& operator++();    // pre-increment
     bool operator==(const OLIterator<T>&) const
     T& operator*() const;   //acccessor 

};

Obviously you can provide more, e.g. decrement/random access etc. but that is pretty much the miniumum, so you can write the first piece of code I suggeted e.g.

OLIterator<Student> IT;
for(IT=studentList.begin();IT!=studentList.end();IT++)
   std::cout<<"Student == "<<*IT<<std::endl;
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.