I truely didn't understand the logic of this line:
Student(int grade = maxGrade) :m_grade(grade){...}
In C++, you can have a function that takes an argument, for example:
static void print_int(int val)
{
std::cout << "value = " << val << std::endl;
}
You can also specify that the function not take any arguments, for example:
static void print_int()
{
std::cout << "value = NOTHING HERE" << std::endl;
}
In this way, I can call print_int
with, or without a value, like so:
print_int();
print_int(42);
output:
value = NOTHING HERE
value = 42
In C++, we can also specify functions that have what are known as default arguments, so that I can write just one function to handle a scenario like above, for example:
static void print_int(int val = 314159)
{
std::cout << "value = " << val << std::endl;
}
So just as above, I can then call print_int
with, or without a value, like so:
print_int();
print_int(42);
output:
value = 314159
value = 42
Given this, we can then look at your Student
constructor1 that you are confused on:
Student(int grade = maxGrade)
And ascertain that if you were to create a Student
object and did not give it an argument (i.e. the grade), then the default value for that student's grade would be whatever the current highest grade is2, for example:
Student alpha(50); // current max grade set to 50
Student beta; // max grade still 50, set 'beta'
Student gamma(42); // 42 < 50, max grade unchanged
Student lambda(96); // 96 > 50, max grade now 96
Student zeta; // max grade still 96, set 'zeta'
alpha.Print(); // Grade = 50
beta.Print(); // Grade = 50
gamma.Print(); // Grade = 42
lambda.Print(); // Grade = 96
zeta.Print(); // Grade = 96
Based on your use of static members, I don't want to assume, but it appears that you understand that concept, so the constructor is the same as saying
Student(int grade = Student::maxGrade)
Thus, if Student::maxGrade
is defined as 0, then the above example works. If, however, the maxGrade
is set to something other than 0 before creating any Student
objects, (e.g. int Student::maxGrade = 50;
), then the above example changes:
// defined somewhere in your code (e.g. above main)
int Student::maxGrade = 50;
// elsewhere in code (e.g. main)
Student alpha(42); // 42 < 50, max grade unchanged
Student beta; // max grade 50, set 'beta' to 50
Student gamma(96); // 96 > 50, max grade now 96
Student lambda; // max grade 96, set 'lambda'
alpha.Print(); // Grade = 42
beta.Print(); // Grade = 50
gamma.Print(); // Grade = 96
lambda.Print(); // Grade = 96
As to the rest of the syntax, the part after the colon (:
), on a constructor that is known as the member initialization list, you can think of that syntax similar to this:
// with initialization list
Student(int grade = maxGrade) : m_grade(grade)
{
...
}
// without initialization list
Student(int grade = maxGrade)
{
this->m_grade = grade;
...
}
The link above is more technical, but this answer has good explanation on "why" use a member initialization list, as well, your professor might be able to answer why, if you have not already gone over that.
Just to add, you could also write your Student
class to have two constructors that give the same effect of the one in question, for example:
Student() : m_grade(maxGrade) { ... }
Student(int grade) : m_grade(grade) { ... }
If that gives any clarity3 to understanding the syntax.
I hope that can help.
1: Hopefully your professor has gone over "the rule of 3/5/0" with you.
2: That's an odd way to grade :/
3: And depending on how you wanted your code to work, you might want to mark the Student(int) constructor as explicit, e.g. explicit Student(int)