List class with Student type

I am trying to use a class Student and declare it as a list type. I can pushback but without changing the List.h or Node.h how can I print the data in list2?

Node.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef NODE_H
#define	NODE_H

#include <string>
#include <iostream>
using namespace std;
template <typename T>
class Node {
private:
  T data;
  Node<T>* next;
public:
  Node(T);
  virtual ~Node(); // base class destructor must be virtual

  template <typename U> friend class List;
};
template <typename T>
Node<T>::Node(T d) {
  data = d;
  next = NULL;
}
template <typename T>
Node<T>::~Node() {
}
#endif	/* STRNODE_H */


List.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#ifndef LIST_H
#define LIST_H

#include "Node.h"

// Singly linked list
template <typename T>
class List {
  private:
    Node<T>* head; // pointer to the first node
    Node<T>* tail; // pointer to the last node
    int count;  // number of nodes in the list
  public:
    class OutOfRangeException{ }; // empty inner class for exception handling
    List();
    virtual ~List();
    void push_back(T item);
    void insert(int index, T item);
    void remove(int index);
    int indexOf(T item);
    T get(int position); // OutOfRangeException is generated
    bool isEmpty();
    int size();
    void print();
};
template <typename T>
List<T>::List() {
  head = tail = NULL;
  count = 0;
}
template <typename T>
List<T>::~List() {
  Node<T>* discard;
  while (head != 0) {
    discard = head;
    head = head->next;
    delete discard;
  }
}

// append an item at the end of the StrList
template <typename T>
void List<T>::push_back(T item) {
  try {
    Node<T>* newNode = new Node<T>(item);
    if (head == 0) {
      head = tail = newNode;
    } else {
      tail->next = newNode;
      tail = newNode;
    }
    ++count;
  } catch (bad_alloc &e) {
    cout << "memory allocation exception: " << e.what() << endl;
    exit(1);
  }
}

// insert an item at the specified index
template <typename T>
void List<T>::insert(int index, T item) {
  try {
    if (index < 0 || index > count) // push_back() if index == count
      throw OutOfRangeException();

    Node<T>* newNode = new Node<T>(item);
    if (head == 0) { // empty
      head = tail = newNode;
    } else if (index == 0) { // at the start
      newNode->next = head;
      head = newNode;
    } else if (index == count) { // at the end
      tail->next = newNode;
      tail = newNode;
    } else { // insert in the middle
      Node<T>* prevNode;
      Node<T>* currNode = head;
      for (int i = 0; i < index; i++) {
        prevNode = currNode;
        currNode = currNode->next;
      }
      // insert between 'prevNode' and 'currNode'
      prevNode->next = newNode;
      newNode->next = currNode;
    }
    ++count;

  } catch (bad_alloc &e) {
    cout << "memory allocation exception: " << e.what() << endl;
    exit(1);
  }
}

// is the StrList empty?
template <typename T>
bool List<T>::isEmpty() {
  return count == 0;
}

// remove the item at specified index
template <typename T>
void List<T>::remove(int index) {
  if (index < 0 || index >= count)
    throw OutOfRangeException();

  if (index == 0) { // at the start
    Node<T>* discard = head;
    head = head->next;
    delete discard;
  } else {
    Node<T>* prevNode;
    Node<T>* currNode = head;
    for (int i = 0; i < index; i++) {
      prevNode = currNode;
      currNode = currNode->next;
    }
    // remove 'currNode'
    prevNode->next = currNode->next; // bypass
    delete currNode;

    if (index == count - 1) // last node was removed. Update 'tail'
      tail = prevNode;
  }
  --count;
  if (count == 0)
    tail = NULL;
}

// retrieve the item at the given position of the StrList. position starts from 0.
// throws OutOfRangeException if invalid position value is given.
template <typename T>
T List<T>::get(int position) {
  if (position < 0 || position >= count)
    throw OutOfRangeException();

  int loc = 0;
  Node<T>* curr = head;
  while (loc < position) {
    ++loc;
    curr = curr->next;
  }
  return curr->data;
}

// Requirement:
//   != operator of <class T>  is used
template <typename T>
int List<T>::indexOf(T item) {
  if (head == 0) {
    return -1; // not found
  } else {
    int index = 0;
    Node<T>* currNode = head;
    while (currNode->data != item && currNode != NULL) {
      currNode = currNode->next;
      ++index;
    }
    if (currNode == NULL) // not found thru the end
      return -1;
    else
      return index;
  }
}

// number of nodes in the StrList
template <typename T>
int List<T>::size() {
  return count;
}

// Requirement:
//   << operator for <class T> is used.
template <typename T>
void List<T>::print() {
  cout << "*** StrList contents ***" << endl;
  for (int i = 0; i < count; i++) {
    cout << i << ": " << get(i) << endl;
  }
}
#endif


Student.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "List.h"

class Student {
private:
	string name;
	int id;
public:
	Student();
    Student(string a);
	virtual ~Student();

};
Student::Student() {
}
Student::Student(string a) {
	name = a;
	
}
Student::~Student() {

}


main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

#include "Student.h"

int main() {

  cout << "\n*** StrList Test ***" << endl;

  List<string> list;
  list.push_back("zero");
  list.push_back("one");
  list.push_back("two");
  list.push_back("three");
  list.push_back("four");
  list.push_back("five");
  list.print();
  
  list.insert(1, "inserted at position 1");
  list.insert(0, "inserted at position 0");
  list.insert(4, "inserted at position 4");
  list.print();

  cout << "removing at indexes 3, 0" << endl;
  list.remove(3);
  list.remove(0);
  list.print();

  list.insert(2, "inserted at position 2");
  list.print();

  cout << "five is at index " << list.indexOf("five") << endl;
  cout << "two is at index " << list.indexOf("two") << endl;
  
  //Test for my Student class implementation
//  Student<string> st1; //Create new student Ryan Martin with id of 1
  List<Student> list2;
  Student stu("Ryan Martin");
  list2.push_back(stu);
  //list2.print();
  //list2.push_back("Ryan");
  //list2.PrintStudents(); //Test that the Student class successfully stored and can access
  return 0;

}
You'll need to define a stream operator for Student, so that the line:

cout << i << ": " << get(i) << endl;

in list.h can work with it.
alright so i added an operator within my student class but my program crashes when it attempts to print it...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "List.h"

class Student {
private:
	string name;
	int id;
public:
	Student();
    Student(string a);
	virtual ~Student();
	friend ostream& operator<<(ostream &os, const Student& p);
};
Student::Student() {
}
Student::Student(string a) {
	name = a;
	
}
Student::~Student() {

}
ostream& operator<<(ostream &os, const Student& p)
{
    return os << p;
}
Sorry i just realized i needed to change p to p.name
Ok so now I have that working my last problem is implementing an != operator so if there are two Students with the same name and id then they are identical. How could i test it with what I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "List.h"

class Student {
private:
	string name;
	int id;
public:
	Student();
    Student(string a);
	virtual ~Student();
	friend ostream& operator<<(ostream &os, const Student& p);
	bool operator!=(const Student &p) const;
	bool operator==(const Student &p) const;
};
Student::Student() {
}
Student::Student(string a) {
	name = a;
	
}
Student::~Student() {

}
ostream& operator<<(ostream &os, const Student& p) {
	return os << p.name;
}
bool Student::operator==(const Student &p) const {
     // Compare the values, and return a bool result.
	if (name == p.name)
		return true;
	else
	return false;
}
bool Student::operator!=(const Student &p) const {
    return !(*this == p);
}
If you require both name and id to be equal you can use && to test both.

1
2
3
4
if (name == p.name && id == p.id)
	return true;
else
	return false;


You don't actually need an if statement. You can just return the condition directly.
return name == p.name && id == p.id;
Awesome that worked great! Thanks for your help on this.
Topic archived. No new replies allowed.