为什么需要在派生类的初始化列表中调用基类的构造函数?

Seg*_*ult 3 c++ constructor

在C++中,假设我有一个具有以下构造函数的Person -

Person::Person(const string& nm, const string& id)
{
   name = nm;
   idNum = id; 
}
Run Code Online (Sandbox Code Playgroud)

现在,我还有一个名为StudentPerson子类,其中包含额外的数据成员majorgradYear.是否有必要让Student类的构造函数在初始化列表中调用基类Person的构造函数,如果是,为什么?

Student::Student(const string& nm, const string& id, const string& maj, int year)
: Person(nm, id){
   major =maj;
   gradYear =year;
}
Run Code Online (Sandbox Code Playgroud)

我不能像这样定义学生的构造函数 -

Student::Student(const string& nm, const string& id, const string& maj, int year)
{
   Person(nm, id);
   major =maj;
   gradYear =year;
}
Run Code Online (Sandbox Code Playgroud)

sbi*_*sbi 9

是否有必要让Student类的构造函数在初始化列表中调用基类Person的构造函数,如果是,为什么?

始终在派生类构造函数之前调用基类构造函数.如果未在初始化列表中显式调用它们,则会隐式调用默认构造函数.如果基类没有默认构造函数,则这不起作用,因此您必须显式指定要调用的基类构造函数.

必须在派生类的构造函数之前调用基类构造函数,因为您可以从派生类的构造函数访问基类子对象.您可以调用它们的公共和受保护的成员函数,为了成功,它们的数据成员当然必须被初始化 - 这正是基类构造函数所做的.


我不能像这样定义学生的构造函数 -

Student::Student(const string& nm, const string& id, const string& maj, int year)
{
   Person(nm, id);
   major =maj;
   gradYear =year;
}
Run Code Online (Sandbox Code Playgroud)

不,你不能.在执行派生类的构造函数的主体之前,从初始化列表中调用基类构造函数.这就是语言定义的方式.
您的语法会创建一个立即丢弃的未命名临时文件.


请注意,在初始化列表中初始化数据成员时,它被认为是好的样式(并且,对于某些类型,也是技术上的必需品).

一个很好的理由是,在C++中,对象具有值语义,它们不是引用.也就是说,变量是指实际对象,而不是对对象的引用,并且变量之间的分配会更改实际对象的内容,而不是使它们引用其他对象.

考虑这种类型:

class Student {
  public:
    Student(const std::string& n)
    {
      name = n; // this is bad!
    }
    // ...
  private:
    std::string name;
    // ...
};
Run Code Online (Sandbox Code Playgroud)

该赋值name = n不分配对字符串的引用,它实际上分配字符串,也就是说,它调用赋值运算符然后复制字符!为了调用names赋值运算符,name当然必须正确构造.因此,编译器会静默插入对构造函数的调用,因此构造函数如下所示:

Student(const std::string& n)
  : name() // therefore 
{
  name = n; // this is bad!
}
Run Code Online (Sandbox Code Playgroud)

现在,这将首先创建一个空字符串,只是为了在下一个语句中立即覆盖它.那太愚蠢了.因此,您最好在初始化列表中初始化所有数据成员(以及基类):

Student(const std::string& n)
  : name(n) // good!
{
}
Run Code Online (Sandbox Code Playgroud)


K-b*_*llo 1

Student类的构造函数是否需要调用初始化列表中基类Person的构造函数,如果需要,为什么?

是否仅当基类无法默认构造时才需要?构造函数初始化列表是唯一可以构造基类的地方。即使你可以不这样做,为什么呢?AStudent是 a ,因此只有构造 a是包含构造 a 的操作Person才有意义。StudentPerson

我不能像这样定义 Student 的构造函数 -

Student::Student(const string& nm, const string& id, const string& maj, intyear) { Person(nm, id); } 专业 = 专业;毕业年份=年份;}

那么你尝试过吗?不,你不能像那样调用基本构造函数。如果有的话,那就是构造一个临时的used Person,而不是基类。