为什么需要在派生类的初始化列表中调用基类的构造函数?
在 C++ 中,假设我有一个带有以下构造函数的类 Person -
Person::Person(const string& nm, const string& id)
{
name = nm;
idNum = id;
}
现在,我还有一个名为 Student 的 Person 子类,带有额外的数据成员<强>专业和毕业年份。 Student类的构造函数是否需要调用初始化列表中基类Person的构造函数,如果需要,为什么?
Student::Student(const string& nm, const string& id, const string& maj, int year)
: Person(nm, id){
major =maj;
gradYear =year;
}
我不能像这样定义 Student 的构造函数 -
Student::Student(const string& nm, const string& id, const string& maj, int year)
{
Person(nm, id);
major =maj;
gradYear =year;
}
In C++, suppose I have a class Person with following constructor -
Person::Person(const string& nm, const string& id)
{
name = nm;
idNum = id;
}
Now, I also have a subclass of Person called Student with extra data members major and gradYear. Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?
Student::Student(const string& nm, const string& id, const string& maj, int year)
: Person(nm, id){
major =maj;
gradYear =year;
}
Can not I define the constructor of Student like this -
Student::Student(const string& nm, const string& id, const string& maj, int year)
{
Person(nm, id);
major =maj;
gradYear =year;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
基类构造函数始终在派生类构造函数之前调用。如果不在初始化列表中显式调用它们,则隐式调用默认构造函数 em>。如果基类没有默认构造函数,则这不起作用,因此您必须显式指定要调用的基类构造函数。
有必要在派生类的构造函数之前调用基类构造函数,因为您可以从派生类的构造函数访问基类子对象。您可以调用它们的公共和受保护的成员函数,为了成功,它们的数据成员当然必须被初始化 - 这正是基类构造函数所做的。
不,你不能。 在执行派生类构造函数的主体之前,从初始化列表中调用基类构造函数。这就是语言的定义方式。
您的语法创建了一个未命名的临时对象,该临时对象会立即被丢弃。
请注意,它也被认为是良好的风格(对于某些类型,也是技术上的必要性)初始化初始化列表中的数据成员。
这样做的一个很好的理由是,在 C++ 中,对象具有值语义,它们不是引用。也就是说,变量引用实际对象,而不是对对象的引用,并且变量之间的赋值会更改实际对象的内容,而不是使它们引用其他对象。
考虑这种类型:
该赋值
name = n
并不分配对字符串的引用,它实际上分配字符串,也就是说,它调用赋值运算符,然后复制字符!为了调用names
的赋值运算符,name
当然必须正确构造。因此,编译器会默默地插入对构造函数的调用,以便构造函数看起来像这样:现在,这将首先创建一个空字符串,只是为了立即在下一个语句中覆盖它。那太愚蠢了。因此,您最好在初始化列表中初始化所有数据成员(以及基类):
Base class constructors are always called before derived class constructors. If you do not call them explicitly in the initialization list, default constructors are called implicitly. If a base class has no default constructor, this doesn't work, so you have to explicitly specify a base class constructor to be called.
It is necessary to invoke base class constructors before the constructors of derived classes because you can access the base class sub-objects from the constructors of derived classes. You can call their public and protected member functions, and for that to succeed, their data members certainly have to be initialized - which is just what base class constructors do.
No, you can't. Base class constructors are called from the initialization list, before the body of the derived class' constructor is executed. That's just the way the language is defined.
Your syntax creates an unnamed temporary that is immediately discarded.
Note that it is considered good style (and, for some types, also a technical necessity) to also initialize data members in the initialization list.
A very good reason for this is that, in C++, objects have value semantics, they are not references. That is, a variable refers to an actual object, not a reference to an object, and assigning between variables changes actual objects' contents, rather than making them refer to other objects.
Consider this type:
That assignment
name = n
does not assign references to strings, it actually assigns the strings, that is, it invokes the assignment operator which then copies the characters! In order to invokenames
's assignment operator,name
certainly has to be properly constructed. Therefore, a call to the constructor is silently inserted by the compiler, so that the constructor looks like this:Now, this will first create an empty string, just to immediately override it in the very next statement. That's stupid. Therefore, you better initialize all your data members (along with your base classes) in the initialization list:
因为你不能调用构造函数。构造初始化列表在几个方面都很特殊,其中之一就是为您提供访问基本构造函数的方法。另外,您应该始终初始化初始化列表中的字段。
Because you cannot call constructors. Construct initialiser lists are special in several ways, and giving you a means to access the base ctor is one of them. Also, you should always initialise fields in the init list.
是否仅当基类无法默认构造时才需要?构造函数初始化列表是唯一可以构造基类的地方。即使你可以不这样做,为什么呢?
Student
是一个Person
,因此只有构建Student
是一个包含构建Person
的操作才有意义>。你尝试过吗?不,你不能像那样调用基本构造函数。如果有的话,那就是构造一个临时未使用的
Person
,而不是基类。Is it only necessary if the base class cannot be default constructed. Constructor initialization lists are the only place where one can construct the base classes. Even if you would be able to not do it, why would you? A
Student
is aPerson
, so it only makes sense that constructing aStudent
is an operation that includes constructing aPerson
.Well have you tried it? No, you cannot call the base constructor like that. If anything, that would be constructing a temporary unused
Person
, not the base class.Student 类的构造函数是否需要调用初始化列表中基类 Person 的构造函数,如果需要,为什么?
简而言之,是的。派生类构造函数将始终尝试首先调用基类构造函数。如果您没有明确告诉它调用您重写的构造函数,它将尝试调用默认构造函数(没有参数)。在你的情况下,这将失败,因为你还没有定义它。
我不能像这样定义 Student 的构造函数吗......
不,因为你不能在这样的代码中调用构造函数。此外,即使你可以,你的代码也会失败,因为编译器将出于上述原因寻找默认构造函数。如果你真的想(我不明白为什么你会这样做)你可以定义一个默认构造函数
Person::Person()
,然后这样:Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?
In short, yes. The derived class constructor will ALWAYS try to call the base class constructor first. If you don't specifically tell it to call your overridden constructor, it will try to call a default constructor (with no params). In your case this will fail as you haven't defined it..
Can not I define the constructor of Student like.....
No, because you can't call a constructor in code like that. And besides, even if you could, your code would fail as the compiler will look for a default constructor for the reasons stated above. If you really wanted to (and I can't think why you would) you could define a default constructor
Person::Person()
, and then have this:Student类的构造函数是否需要调用初始化列表中基类Person的构造函数,如果需要,为什么?
基类的构造函数需要在派生类的构造函数之前调用类,因此您需要在派生类的初始化列表中调用它,否则编译器将在您进入派生类主体之前调用基类的默认构造函数。
我不能像这样定义 Student 的构造函数 -
不,你不能。
第二种方法将创建一个新的临时本地对象
Person
,而不是为正在创建的对象调用基类构造函数。Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?
The constructor of the base class needs to be called before the constructor of the derived class, so you need to call it in the initialization list of the derived or the compiler will call default constructor for base class before you enter derived class body.
Can not I define the constructor of Student like this -
No You cannot.
The second approach will create a new temporary local object of
Person
not call Base class constructor for the object being created.