Why does this work this way??

I'm doing homework assignment dealing with classes and inheritance. I have everything working like it is suppose to. My output matches the sample output. This is were I'm confused. I'm suppose to make a class function that calculates a GPA depending on a grad or undergraduate selection.
This is what i have in one of the classes (they are both the same)
1
2
3
4
5
6
7
8
double UnderGradStudent::calcGPA ()
{
	double GPA = 0.0;
	if (CreditHrs > 0)
		GPA = QualityPts / CreditHrs;
	cout << "UnderGraduateStudent calcGPA";
	return (GPA);
}

this next part is my print out in my main.
1
2
cout <<  "\nName: " << b.getName() << " SSN: " << b.getSSN() << " GPA: "
				<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << a.calcGPA() << endl;


https://dl.seminolestate.edu/access/content/user/grantd/cop2224/OnlineAssignments/ShortAssignment9/images/sa9_output_5.png

this is what the sample output is suppose to look like. As you can see it is suupose to print something telling you which class the calcGPA is coming from. Mine looks exactly like this, but when i did this i was wondering how i was got to get the "UnderGrad calcGPA" to print first and then be able to print the returned value in the separate places. For some reason my cout line with the call to the function at the end puts the string first. Can someone help me understand this?
Last edited on
Can you show us the full code?
Sorry took so long went to bed. LOL
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
199
200
201
202
203
204
205
206
207
#include "stdafx.h"

#include <iostream>
#include <iomanip>
using namespace std;
const int SIZE = 80;

class Student
{
protected:
	
	long social;
	char name[SIZE];
	char *NamePtr;
public:
	Student (long = 999999999 , char [] = "unassigned");
	void setSSN(long);
	long getSSN();
	void setName(char[]);
	char* getName();
	double calcGPA();
};

Student::Student(long ssn, char  studentname[SIZE])
{
	social = ssn;
	strcpy (name, studentname);
}

void Student::setSSN(long SSN)
{
		social = SSN;
		return;
}

long Student::getSSN()
{
	return (social);
}

void Student::setName(char name2[SIZE])
{
		strcpy (name, name2);
		return;
}

char* Student::getName()
{	
	NamePtr = name;
	return (NamePtr);
}

double Student::calcGPA()
{
	cout << "Student calcGPA" << endl;
	return (0);
}

class GradStudent : public Student 
{
private:
	char status;
public:
	GradStudent (char = 'A');
	double calcGPA();
	void SetStatus(char);
};

GradStudent::GradStudent(char grade)
{
	status = grade;
}

double GradStudent::calcGPA()
{
	double GPA = 0.0;
	if (status == 'A' || status == 'a')
		GPA = 4.0;
	cout << "GradStudent calcGPA";
	return (GPA);
}

void GradStudent::SetStatus (char stat)
{
	status = stat;
	return;
}

class UnderGradStudent : public Student
{
private:
	double CreditHrs;
	double QualityPts;
public:
	UnderGradStudent ( double = 0, double = 0);
	double calcGPA ();
	void setCredits(int);
	void setQuality(int);
};

UnderGradStudent::UnderGradStudent(double Hours, double Points)
{
	CreditHrs = Hours;
	QualityPts = Points;
	if (Hours < 0)
		CreditHrs = 0;
	if (Points < 0)
		QualityPts = 0;
}

double UnderGradStudent::calcGPA ()
{
	double GPA = 0.0;
	if (CreditHrs > 0)
		GPA = QualityPts / CreditHrs;
	cout << "UnderGraduateStudent calcGPA";
	return (GPA);
}

void UnderGradStudent::setCredits (int C)
{
	CreditHrs = C;
	if (C < 0)
		CreditHrs = 0;
	return;
}

void UnderGradStudent::setQuality (int Q)
{
	QualityPts = Q;
	if (Q < 0)
		QualityPts = 0;
	return;
}

int main()
{
	char contin, grade;
	char StudentName[SIZE];
	long StudentSSN;
	int code, credits, points;
	
	do
	{
	cout << "Enter 1 for undergrad.\nEnter 2 for grad." << endl << "-->";
	cin >> code;
	
		if (code == 1)
		{
			UnderGradStudent a;

			cin.ignore();
			cout << "Enter Student name: ";
			cin.getline(StudentName, SIZE);
			a.setName(StudentName);
	
			cout << "Enter Student SSN: ";
			cin >> StudentSSN;
			a.setSSN(StudentSSN);

			cout << "Enter credit hours: ";
			cin >> credits;
			a.setCredits(credits);

			cout << "Enter quality points: ";
			cin >> points;
			a.setQuality(points);
			cout << endl;

			cout <<  "\nName: " << a.getName() << " SSN: " << a.getSSN() << " GPA: "
				<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << a.calcGPA() << endl;
		}


		if (code == 2)
		{
			GradStudent a;

			cin.ignore();
			cout << "Enter Student name: ";
			cin.getline(StudentName, SIZE);
			a.setName(StudentName);
	
			cout << "Enter Student SSN: ";
			cin >> StudentSSN;
			a.setSSN(StudentSSN);

			cout << "Enter Status: ";
			cin >> grade;
			a.SetStatus(grade);
			cout << endl;

			cout <<  "\nName: " << a.getName() << " SSN: " << a.getSSN() << " GPA: "
				<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << a.calcGPA() << endl;
		}

	cout << "Continue?: ";
	cin >> contin;
	cin.ignore();
	cout << endl;
	}
	while (contin == 'y' || contin == 'Y');
	
		 
	system ("pause");
	return 0;
}
There is actually no magic happening here. You have inherited all your classes from "Student", but in this case it does not change anything, because each class has (not-dynamic) methods. You would have done just as well to write each class without any inheritance, duplicating the information in the child class that was in the parent class.

The following is essentially the same as you have above, except that I had to repeat some information:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Student
{
protected:
	long social;
	char name[SIZE];
	char *NamePtr;
public:
	...
};

class GradStudent:
{
protected:
	long social;
	char name[SIZE];
	char *NamePtr;
private:
	char status;
public:
	...
};

In your code, the computer can tell the difference between which class is which because there is never any possibility of confusing them.
148
149
150
		if (code == 1)
		{
			UnderGradStudent a;
170
171
172
			cout <<  "\nName: " << a.getName() << " SSN: " << a.getSSN() << " GPA: "
				<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << a.calcGPA() << endl;
		}
That is, the variable "a", which only exists between lines 149 and 172, is a known "UnderGradStudent".

Keep in mind that this is a different variable than the "a" that exists between lines 176 and 195, which is a known "GradStudent".

There is never any chance of confusing them.


What polymorphism allows you to do is write variables that could be confused, because they might be different types. Back to the "Student"s: Using virtual (or "dynamic") methods, we can make "a" a pointer to a "Student". Since an "UnderGradStudent" and a "GradStudent" are also "Student"s, the new variable "a" could point to any one of those.

In order to help the compiler tell the difference, you must let it know that certain methods are bound to the actual type of Student and not just a "Student".

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
class Student
{
protected:
	long social;
	char name[SIZE];
	char *NamePtr;
public:
	Student (long = 999999999 , char [] = "unassigned");
	void setSSN(long);
	long getSSN();
	void setName(char[]);
	char* getName();

	// We tell the compiler that the following function is special:
	// Even though the compiler is looking at a Student*, the actual
	// type of thing being pointed to might be a class that inherits from
	// Student, so the computer must check and use the correct "calcGPA"
	// function each time.
	virtual double calcGPA();
};

class GradStudent : public Student 
{
private:
	char status;
public:
	GradStudent (char = 'A');
	void SetStatus(char);

	// Same as above.
	virtual double calcGPA();
};

class UnderGradStudent : public Student
{
private:
	double CreditHrs;
	double QualityPts;
public:
	UnderGradStudent ( double = 0, double = 0);
	void setCredits(int);
	void setQuality(int);

	// Same as above.
	virtual double calcGPA ();
};
Now we can use a single "a" variable to refer to either an "UnderGradStudent" or a "GradStudent", and the program will check each time to see what kind of "Student" it is really looking at and call the correct function:
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
int main()
{
	char contin, grade;
	char StudentName[SIZE];
	long StudentSSN;
	int code, credits, points;

	// Here is our pointer to a "Student". Keep in mind it may actually
	// be a "GradStudent" or an "UnderGradStudent" as well.
	// Initially, there is no student of any kind, so we'll set it to NULL.
	Student* a = NULL;

	do
	{
		cout << "Enter 1 for undergrad.\nEnter 2 for grad." << endl << "-->";
		cin >> code;
	
		if (code == 1)
		{
			a = new UnderGradStudent;

			cin.ignore();
			cout << "Enter Student name: ";
			cin.getline(StudentName, SIZE);
			a->setName(StudentName);		// Notice how we now use "->" instead of "."
			...
			// And so on. Don't print anything here. Just get the student information from the user.
		}

		else if (code == 2)
		{
			a = new GradStudent;
			...
			// Same as above. Just get the grad student information and don't print anything.
		}

		// Don't let the user get away with entering an invalid answer...
		else continue;

		// Now we use our special magic. The compiler would normally think that we are looking
		// at a "Student", but remember we told it that it might be an "UnderGradStudent"
		// or a "GradStudent", so the compiler will automatically check that it calls the correct
		// function:
		cout <<  "\nName: " << a->getName() << " SSN: " << a->getSSN() << " GPA: "
			<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << a->calcGPA() << endl;

		// Remember also that anything allocated with new must be deallocated as well
		delete a;
		a = NULL;

		cout << "Continue?: ";
		cin >> contin;
		cin.ignore();
		cout << endl;
	}
	while (contin == 'y' || contin == 'Y');

	// Please don't use system()
	// http://www.cplusplus.com/forum/articles/7312/
	cout << "Press ENTER to quit.";
	cin.ignore( 1000, '\n' );
	return 0;
}
You should see that the computer is smart enough to tell your student types apart, because you used virtual functions, which told the compiler that you want it to check to see what kind of thing you are using.

If you use the code above without virtual functions, you would find that the computer didn't bother to check to see what kind if student it was actually looking at, because it thinks you are pointing to a "Student" only. Hence, it would always print "Student calcGPA".


I hope this helps you understand better the point of inheritance and polymorphism (many forms -- or using virtual functions to tell the compiler to check to see exactly what kind of thing it is working with instead of assuming it is using the kind of thing it says it is).

:-)
Wow thanks a lot. I have been scared of the use of pointers this really helped me understand it. Just to mention it when i started this class i read about not using system() and used the way the article states but the teacher said not to use stuff we haven't learned in class. But unfortunately my question didn't get answered. Or maybe it did but I'm missing it. In the cout on line 44 and 45. I would think that it would look like this

Name: John Doe SSN: 123456789 GPA: Undergrad calcGPA 3.49

instead it does this

Undergrad calcGPA
Name: John Doe SSN: 123456789 GPA: 3.49

this last output is what the professor asked for i was wondering why it did it this way instead of the former. But again thank you very much for your explanation it answered a lot of questions for me.
Topic archived. No new replies allowed.