Grading system with templates v.2

I need some help with my current output. It's because of lines 52-59 and I know why this happens, but I struggle with what I should do to change it. I want each grade to correspond to its class,but all grades go into all classes.

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
  #include<iostream>
#include<string>
#include <vector>
using namespace std;

template <class T>
class grades
{
public:
	grades();
	void input(T, vector<string>v);
	void input2(T);
	//string getname() { return name; }
private:
	T* arr;
	int size = 4;
	int top;
	
};

template <class T>
grades<T>::grades()
{
	arr = new T[size];
	top = -1;
}

template <class T>
void grades<T>::input2(T name)
{
	cout << "Enter in your name: ";
	getline(cin, name);

}


template <class T>
void grades<T>::input(T grade, vector<string>v)
{
	v = { "Math","English","History","Science" };
	cout << "Enter in the grades for the following: " << endl;
	cout << "----------------------------------------" << endl;
	cout << "Math, English, History, Science" << endl;
	cout << "----------------------------------------" << endl;
	for (int i = 0; i < size; i++)
	{
		cin >> grade;
		arr[++top] = grade;
		cout << endl;
	}
	
	for (int i = 0; i < size; i++)
	{
		cout << v[i] << " :" << endl;
		for (int j = 0; j < size; j++)
		{
			cout << arr[j] << endl;
		}
	}

}

int main()
{
	char anwser;
	int grade = 0; 
	string name;
	vector<string>v;
	do {
		
		grades<int>enter;
		grades<string>enter2;
		enter2.input2(name);
		enter.input(grade,v);
		cout << "wish to keep going?(Y/N): ";
		cin >> anwser;
	} while (anwser == 'Y' || anwser == 'y');
}


This is the output I currently get:
Math:
54
43
75
65
English:
54
43
75
65
History:
54
43
75
65
Science:
54
43
75
65

I've been asking around on how to remedy this both on this site and others with some helpfulness, but some answers were broad while others I asked for clarification and have yet to receive and answer.
The problem you have, whatever design decisions you make, about classes and containers is that the situation is 3 dimensional - subject/student/grade.

e.g. If it is all int's then "in subject 3, student 5, achieved a grade of 95 marks" where each dimension is linked.
In my absence for the few days I did do a little more with the coding and I think I'm close. I've been trying to return the vector of school classes(which I think is correct) but I cannot figure out exactly what to do to display it in the main function. I've tried to do so, but got the error message for line 98 basically saying that "<<" is incompatible with the get() function for the vector.

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
#include<iostream>
#include<string>
#include <vector>
using namespace std;

template <class T>
class grades
{
public:
	grades()
	{
		arr = new T[size];
		top = -1;
	}
	void input();
	int getgrades();
private:
	T* arr;
	int size = 4;
	int top;
	T grade;
};

template <class U>
class student
{
public:
	void names();
	string getname() { return name; };
	void classes();
	const vector<string> getvect();
private:
	U name;
	int size = 4;
	const vector<string>v;
};

template <class U>
void student<U>::names()
{
	cout << "Enter in your name: ";
	getline(cin, name);
}

template <class U>
void student<U>::classes()
{
	v = { "Math","English","History","Science" };
}

template <class U>
const vector<string> student<U>::getvect()
{
	for (int i = 0; i < size; i++)
	{
		cout << v[i] << " :" << endl;
	}
	return v;
}

template <class T>
void grades<T>::input()
{
	cout << "Enter in the grades for the following: " << endl;
	cout << "----------------------------------------" << endl;
	cout << "Math, English, History, Science" << endl;
	cout << "----------------------------------------" << endl;
	for (int i = 0; i < size; i++)
	{
		cin >> grade;
		arr[++top] = grade;
		cout << endl;
	}
}


template <class T>
int grades<T>::getgrades()
{
	for (int i = 0; i < size; i++)
	{
		cout << arr[i] << endl;
	}
	return grade;
}

int main()
{
	char anwser;
	int grade = 0; 
	string name;
	grades<int>gr;
	student<string>students;
	do {
		students.names();
		gr.input();
		cout << students.getname() << endl;
		cout << students.getvect() <<gr.getgrades();
		cout << "wish to keep going?(Y/N): ";
		cin >> anwser;
	} while (anwser == 'Y' || anwser == 'y');
}
the two get’s do the printing so cout << ... get doesn’t make sense.

All you do is call the get method i.e. gr.getgrades(); etc is all you need
Oh okay. Now I've done that it now says when I complete the inputs that the vector subscript is out of range as the run time error pops up.
Go to the get methods and explain what size is.
What do you mean exactly? In the for loop in line 54 it knows that size=4 as seen in line 34 under private in class student.
So add a line to the gets and print out the value of size while commenting out the loop What value is the get method using, how many items are there?

As an overall comment you need to unit test small parts instead of the program all at once. Test each class separately, its the normal way to debug
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include<iostream>
#include<string>
#include<random>
#include<iomanip>

// LISTING ...
template <class T>
class Listing
{
private:
    T* arr = nullptr;
    size_t size = 4; // ARBITRARILY ALLOWS FOR 4 ITEMS
    int top = 0;
    std::string identifier;
    
public:
    Listing(std::string anIdentifier, size_t aSize)
    {
        size = aSize;
        identifier = anIdentifier;
        arr = new T[size];
        top = 0;
    }
    
    ~Listing()
    {
        delete[] arr;
        arr = nullptr;
        std::cout << getIdentifier() << " deleted\n";
    }
    
    void addItem(T anItem)
    {
        arr[top] = anItem;
        top++;
    }
    
    T getItem(size_t anIndex)
    {
        return arr[anIndex];
    }
    
    std::string getIdentifier()
    {
        return "LIST: " + identifier;
    }
    
    size_t getListSize(){return top;}
};
// ... LISTING



// ITEM ...
struct nothing{}; // DEFAULT TYPE IN CONSTRUCTOR
template <class U, class V = nothing, class W = nothing>
class Item
{
private:
    U item_U;
    V item_V;
    W item_W;
    
public:
    Item(){};
    
    Item(U aU, V aV, W aW){item_U = aU, item_V = aV, item_W = aW;}
    
    ~Item(){};
    
    void set_U(U anItem_U){ item_U = anItem_U;}
    void set_V(U anItem_V){ item_V = anItem_V;}
    void set_W(U anItem_W){ item_W = anItem_W;}
    
    U get_U(){ return item_U;}
    V get_V(){ return item_V;}
    W get_W(){ return item_W;}
};
// ... ITEM



// MAIN ...
typedef Item<std::string> Subject;
typedef Item<std::string> Student;
typedef Item<Student, Subject, int>  Grade;

int main()
{
    // SUBJECTS
    std::string subject_names[]
    {"Math", "English", "History", "Science", "Art", "Soccer"};
    
    const size_t no_subjects = sizeof(subject_names)/sizeof(std::string);
    Listing<Subject> list_of_subjects("** Random Subjects **", no_subjects);
    
    Subject sbj_temp;
    for(size_t i = 0; i < no_subjects; i++)
    {
        sbj_temp.set_U(subject_names[i]);
        list_of_subjects.addItem(sbj_temp);
    }
    
    std::cout << list_of_subjects.getIdentifier() << '\n';
    for (size_t i = 0; i < no_subjects; i++)
    {
        std::cout << list_of_subjects.getItem(i).get_U() << '\n';
    }
    std::cout << '\n';
    
    
    
    // STUDENTS
    std::string student_names[]
    {"Alice Malice", "Greg Combet", "Bob Ellis", "Megan Ryan",
        "Catherine Arogan", "James Milligan", "Bill Molony", "Betty Boop"};
    
    const size_t no_students = sizeof(student_names)/sizeof(std::string);
    Listing<Subject> list_of_students("** Random Students **", no_students);
    
    Student stu_temp;
    for(size_t i = 0; i < no_students; i++)
    {
        stu_temp.set_U(student_names[i]);
        list_of_students.addItem(stu_temp);
    }
    
    std::cout << list_of_students.getIdentifier() << '\n';
    for (size_t i = 0; i < no_students; i++)
    {
        std::cout << list_of_students.getItem(i).get_U() << '\n';
    }
    std::cout << '\n';
    
    
    
    // GRADES
    const size_t no_grades = 50;
    
    Listing<Grade> list_of_grades("** Random Grades **", no_grades);
    
    
    
    // GENERATE A RANDOM LIST OF GRADES
    for(int i = 0; i < no_grades; i++)
    {
        std::random_device random_device;
        std::mt19937 random_engine
        { random_device() };
        
        std::uniform_int_distribution<int> st_distribution
        { 0, (int)list_of_students.getListSize()-1 };
        
        int st = st_distribution(random_engine);
        
        std::uniform_int_distribution<int> sj_distribution
        { 0, (int)list_of_subjects.getListSize()-1 };
        
        int sj = sj_distribution(random_engine);
        
        std::uniform_int_distribution<int> mk_distribution{ 0, 100 };
        int mk = mk_distribution(random_engine);
        
        Grade gr_tmp(list_of_students.getItem(st),list_of_subjects.getItem(sj), mk);
        list_of_grades.addItem(gr_tmp);
    }
    
    Grade gr_tmp;
    std::cout << list_of_grades.getIdentifier() << '\n';
    for (size_t i = 0; i < list_of_grades.getListSize(); i++)
    {
        gr_tmp = list_of_grades.getItem(i);
        std::cout
        << std::setw(20) << gr_tmp.get_U().get_U() << ' '
        << std::setw(10) << std::left << gr_tmp.get_V().get_U()
        << std::setw(10) << std::right << gr_tmp.get_W() << '\n';
    }
    std::cout << '\n';
    
    // FOR A PARTICULAR STUDENT 'Betty Boop'
    for (size_t i = 0; i < list_of_grades.getListSize(); i++)
    {
        gr_tmp = list_of_grades.getItem(i);
        if( gr_tmp.get_U().get_U() == "Betty Boop" )
        {
            std::cout
            << std::setw(20) << gr_tmp.get_U().get_U() << ' '
            << std::setw(10) << std::left << gr_tmp.get_V().get_U()
            << std::setw(10) << std::right << gr_tmp.get_W() << '\n';
        }
    }
    std::cout << '\n';
    
    
    std::cout << "END\n";
    return 0;
}
// ... MAIN 


LIST: ** Random Subjects **
Math
English
History
Science
Art
Soccer

LIST: ** Random Students **
Alice Malice
Greg Combet
Bob Ellis
Megan Ryan
Catherine Arogan
James Milligan
Bill Molony
Betty Boop

LIST: ** Random Grades **
           Bob Ellis Science           49
         Bill Molony Art              100
           Bob Ellis Soccer            12
        Alice Malice History            7
           Bob Ellis History           50
          Betty Boop English           39
         Greg Combet Science           18
          Megan Ryan Math              68
        Alice Malice History           20
           Bob Ellis Soccer            88
           Bob Ellis Science            5
        Alice Malice Soccer            65
           Bob Ellis Science           70
           Bob Ellis Art                9
           Bob Ellis Soccer            74
         Greg Combet Science           41
           Bob Ellis Science           79
    Catherine Arogan Soccer            67
        Alice Malice Art                1
         Bill Molony English           42
         Bill Molony English           43
      James Milligan Art               56
         Bill Molony Art               19
    Catherine Arogan Math               1
         Greg Combet English           25
    Catherine Arogan Art               84
         Bill Molony Art               65
         Bill Molony Soccer            56
    Catherine Arogan English           50
        Alice Malice Science            9
           Bob Ellis Science           20
          Megan Ryan Art               19
          Betty Boop English           85
    Catherine Arogan Soccer            46
    Catherine Arogan Art               55
         Bill Molony History           26
         Greg Combet English           68
           Bob Ellis Science           78
          Betty Boop History           34
         Bill Molony Science           62
         Greg Combet History           22
    Catherine Arogan English            8
        Alice Malice Math              58
          Megan Ryan Science           31
          Megan Ryan Soccer            44
        Alice Malice Art                8
          Betty Boop Soccer            64
    Catherine Arogan Art               72
          Betty Boop Soccer            66
      James Milligan History           45

          Betty Boop English           39
          Betty Boop English           85
          Betty Boop History           34
          Betty Boop Soccer            64
          Betty Boop Soccer            66

END
LIST: ** Random Grades ** deleted
LIST: ** Random Students ** deleted
LIST: ** Random Subjects ** deleted
Program ended with exit code: 0
your classes don't have relationships
you have `student' and `grades' but they don't interact
stop coding and go back to the drawing board

apart from that
1
2
3
4
5
6
7
8
template <class T>
class grades
{
	T* arr;
	int size = 4;
	int top;
	T grade; //¿?
};

¿why is it a template?
¿why do you use dynamic allocation if you always want 4 elements?
you may just simply do T arr[4];
¿what's the `grade' member variable purpose?

¿what types do you expect T to hold?


1
2
3
4
template <class U>
class student
{
	U name;
¿why did you change the template letter?
¿what types a name may be?



> typedef Item<Student, Subject, int> Grade;
that doesn't scale too well
Building on ne555's comments:

class grade:
- You have dynamically allocated array of grades, and an individual member called grade. How are these related? When do you use arr and when do you use grade?
class student:
- Method names() is poorly named. It gets one name, not many.
- Since names() calls getline(cin,name), name must be a string. There's no reason for student to be a template if it only supports one template type.
- why have the classes() method? why not set v inside the constructor?
- Since it can only ever have 4 items, you could use an array instead of a vector, although that can lead to slightly more error prone code.
- names like v and getvect() aren't very useful. What does the vector represent?
- In method input: cout << "Math, English, History, Science" << endl; is fragile - meaning that it works but it's easily broken. What you mean to print is the contents of v. If you changed, for example to alphabetize it, to {"English","History","Math",Science"} then this line in input would be wrong.
method getgrades() is poorly named. First of all, don't put the class name in a method of the class. It's completely redundant. You wouldn't call this grades<T>::getGradesMethodForGradesClass(). Calling it getgrades() is only a little better. Second, "get" usually returns a value, and this one does, but it has the curious side effect of also printing out all the grades in arr. This should be called something like void print(ostream &); member grade is unnecessary and just confuses things.

Finally, ideally class student should have an instance of grades inside it. That instance would represent the grades for the student. Once you do this, methods to input and print a student will call the methods to input/print their grades.

Putting it all together:
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
#include<iostream>
#include<string>
#include <vector>
using namespace std;

// This handles 4 grades. They can be numbers, letters, strings, whatever
template <class T>
class grades
{
public:
    void input();
    void print(ostream &os);
private:
    static constexpr unsigned size=4;
    T arr[size] {};
};

template<class T>
class student
{
public:
    student();
    void input();		// get the student name and grades
    string getname() { return name; };
    void print(ostream &);
private:
    string name;
    vector<string> classNames;
    grades<T> gr;
};

template <class T>
void student<T>::input()
{
	cout << "Enter in your name: ";
	getline(cin, name);
	cout << "Enter in the grades for the following: " << endl;
	cout << "----------------------------------------" << endl;
	cout << classNames[0];
	for (unsigned i=1; i<classNames.size(); ++i) {
	    cout << ", " << classNames[i];
	}
	cout << '\n';
	cout << "----------------------------------------" << endl;
	gr.input();		// now read the grades
}

template <class T>
student<T>::student()
{
    classNames = { "Math","English","History","Science" };
}

template <class T>
void student<T>::print(ostream &os)
{
    for (unsigned i = 0; i < classNames.size(); i++) {
	os << classNames[i] << '\t';
    }
    os << '\n';
    gr.print(os);
}

template <class T>
void grades<T>::input()
{
	for (unsigned i = 0; i < size; i++)
	{
	    T grade;
	    cin >> grade;
	    arr[i] = grade;
	}
}


template <class T>
void grades<T>::print(ostream &os)
{
	for (unsigned i = 0; i < size; i++)
	{
	    os << arr[i] << '\t';
	}
	os << '\n';
}

int main()
{
	char anwser;
	student<int> myStudent;
	do {
		myStudent.input();
		myStudent.print(cout);
		cout << "wish to keep going?(Y/N): ";
		cin >> anwser;
	} while (anwser == 'Y' || anwser == 'y');
}

$ ./foo
Enter in your name: Dave
Enter in the grades for the following:
----------------------------------------
Math, English, History, Science
----------------------------------------
92 78 83 95
Math    English History Science
92      78      83      95
wish to keep going?(Y/N): n



This still isn't ideal. There should be a class that binds a school class name and a grade:
1
2
3
4
class StudentClass {
string name;
int grade;
};


This would replace both the grade class and the className vector. Instead a student would have a vector of StudentClass's:
1
2
3
4
class Student {
...
    vector<StudentClass> classes;   // classes that the student is enrolled in
};

typedef Item<Student, Subject, int> Grade;
that doesn't scale too well


Perhaps, perhaps not, who knows? Just saying 'scale' doesn't mean much, certainly anything of tangible value.

Probably not worthy of a response other than a search of 200,000 random Grades at the time takes seconds, 2,000,000 20s, so for this exercise I have no complaint. Most would be happy.

Also, I alluded to the possibility of a typedef of "int's" in a comment above. They would be keys in the typedef instead of the Items themselves. Perhaps even pointers. All of which are simple ways of binding the 3 dimensions, as I described them.

The problem with that is I doubt whether the OP would have seen any sort of a way out of the tangled web he/she has derived. In any case I think the OP has lit the fuse and the outcome is (quite rightly) his/hers to advance the way he/she sees fit.

Of course none of this stops you from making a value-add contribution.
Topic archived. No new replies allowed.