我是学生,我们以这节课作为我们学习的某些主题的示例:
class Student {
private:
static int maxGrade;
static Student* bestStudent;
public:
const int m_grade;
static int nofStudents;
Student(int grade = maxGrade) :m_grade(grade) {
if (grade > maxGrade) {
maxGrade = grade;
bestStudent = this;
}
nofStudents++;
}
Student(const Student& std) : m_grade(std.m_grade) {
nofStudents++;
}
~Student() {
if (bestStudent == this) {
maxGrade = 0;
bestStudent = NULL;
}
nofStudents--;
}
void Print()const { cout << "Grade = " << m_grade << endl; }
};
int main()
{
Student Rafi;
Student Moshe(97);
Student Avi(89);
return 0;
}
即使调试并查看了过程,我也无法理解Student类的构造函数如何工作,我确实不了解这一行的逻辑:
Student(int grade = maxGrade) :m_grade(grade){...}
出于某种我不了解的原因,在对构造函数的evrey调用中,grade保留了最后一次调用的值,尽管存在“ int grade = maxGrade”。
非常感谢这种语法。
答案 0 :(得分:4)
我真的不明白这行的逻辑:
Student(int grade = maxGrade) :m_grade(grade){...}
在C ++中,可以有一个带有参数的函数,例如:
static void print_int(int val)
{
std::cout << "value = " << val << std::endl;
}
您还可以指定该函数不接受任何参数,例如:
static void print_int()
{
std::cout << "value = NOTHING HERE" << std::endl;
}
这样,无论有没有值,我都可以调用print_int
,就像这样:
print_int();
print_int(42);
output:
value = NOTHING HERE
value = 42
在C ++中,我们还可以指定具有所谓的default arguments的函数,以便我可以只编写一个函数来处理上述情况,例如:
static void print_int(int val = 314159)
{
std::cout << "value = " << val << std::endl;
}
因此,如上所述,然后我可以调用带有或不带有值的print_int
,就像这样:
print_int();
print_int(42);
output:
value = 314159
value = 42
鉴于此,我们可以查看您对Student
感到困惑的构造函数 1 :
Student(int grade = maxGrade)
并确定如果要创建一个Student
对象并且没有给它提供参数(即成绩),则该学生的成绩的默认值将是当前最高成绩的任何值 2 ,例如:
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
基于您对static members的使用,我不想假设,但是看来您了解该概念,因此构造函数与所说的相同
Student(int grade = Student::maxGrade)
因此,如果将Student::maxGrade
定义为0,则以上示例适用。但是,如果在创建任何maxGrade
对象(例如Student
)之前将int Student::maxGrade = 50;
设置为非0的值,则上述示例将更改:
// 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
对于其余语法,在称为member initialization list的构造函数中,冒号(:
)之后的部分,您可以想到类似于以下语法: >
// with initialization list
Student(int grade = maxGrade) : m_grade(grade)
{
...
}
// without initialization list
Student(int grade = maxGrade)
{
this->m_grade = grade;
...
}
上面的链接是更具技术性的,但是this answer也很好地解释了“为什么”使用成员初始化列表,如果您还没有讲解的话,您的教授也许可以回答原因。
只需添加一下,您还可以编写Student
类,使其具有两个具有与所讨论的相同效果的构造函数,例如:
Student() : m_grade(maxGrade) { ... }
Student(int grade) : m_grade(grade) { ... }
如果可以理解的话 3 。
我希望能对您有所帮助。
1:希望您的教授和您一起过"the rule of 3/5/0"。
2:这是一种奇怪的评分方式:/
3:根据您希望代码的工作方式,您可能希望将 Student(int)构造函数标记为explicit,例如明确学生(int)
答案 1 :(得分:1)
如果您在函数或构造函数中为参数“分配”一个值,那么您将为 default 值指定一个值,该值用于在调用函数/构造函数时不提供其他任何值。
如果在呼叫站点提供了另一个值 ,则该值将被分配给该参数。
在您的示例中:
Student Rafi;
Student Moshe(97);
Student Avi(89);
对构造函数的第一次调用会将grade
参数设置为maxGrade
的当前值,因为没有提供任何值。第二个将grade
设置为97,第三个将其设置为89。
答案 2 :(得分:0)
您引用了以下行:Student(int grade = maxGrade):m_grade(grade){...}
从您的评论中听起来,构造器中的参数是造成混乱的根源,可能与所包含的等号有关。如果未提供任何值,则此参数指定用于评分的默认值。这样的效果是允许您的类的用户不带参数调用该构造函数。请注意,仅允许您为最后一个参数指定默认值(如果存在多个)。
在您的情况下,maxGrade是一个静态变量,因此只有一个实例可供所有Student对象引用。在构造Student对象时,此值可能会根据构造函数主体中的逻辑而改变。如果您首先以最好的成绩构建学生,则不会看到此maxGrade更改。如果您首先建立一些低年级的学生,并且每次都逐步提高,那将会发生什么。