构造函数中语法不明确

时间:2018-12-18 16:25:54

标签: c++

我是学生,我们以这节课作为我们学习的某些主题的示例:

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”。

非常感谢这种语法。

3 个答案:

答案 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更改。如果您首先建立一些低年级的学生,并且每次都逐步提高,那将会发生什么。