作为 class 数据成员的对象,使用带和不带初始化列表的默认构造函数
objects as class data members using default constructor with and without initializer list
以下节目
#include <iostream>
using namespace std;
class university{
private:
string uni;
public:
university(){
cout<<"default constructor of university is invoked"<<endl;
}
university(string u){
uni =u;
cout<<"parametrized constructor of university is invoked: "<<uni;
}
};
class student{
private:
university u;
public:
student() {
u = university("ABC");
}
};
int main()
{
student s;
return 0;
}
输出是:
default constructor of university is invoked
parametrized constructor of university is invoked: ABC
但是当更改 student class 的构造函数以使用如下初始化列表时:
student(): u(university("ABC")){
}
输出是:
parametrized constructor of university is invoked: ABC
我的问题是:
对于第二种情况,当编译器在 student class 的私有部分运行 university u
行时,它是否创建了 class 'university' 的对象 'u' 和为其分配内存地址,还是在初始化列表中创建对象?如果是前者,那为什么不调用默认构造函数呢?
对于第一种情况,我有同样的问题,对象是在哪里创建并分配内存位置的。
“分配内存”和“分配内存位置”与此处无关。您问的是如何构建作为另一个 class 成员的对象。试图在这里引入内存分配的主题只会使事情变得混乱。高级 C++ 技术允许“在同一位置”重复构造和销毁对象(通过 placement new 和显式析构函数调用)。实际内存位置和对象 constructions/destructions 完全无关紧要。它们彼此无关,如果您只是忘记有关内存位置的所有内容,而只关注对象构造和销毁的主题,这将很有帮助。说了这么多:
对象构造函数负责构造对象的所有成员。这是规则。没有例外。句号。
student(): u(university("ABC")){
这会奏效,但在令人困惑的成员中也会这样做。这阐明了以下事件顺序:构造临时 university
对象,然后 copy-constructs student
class 的实际成员,最后临时对象被销毁。这是不必要的,只会把水搅浑。使用更简单、现代的 C++ 语法,这应该是:
student(): u{"ABC"}{
这种更短、更直接的语法以简单、简洁的方式准确地描述了正在发生的事情:对象的构造函数构造了该对象的所有成员,即这里只有一个成员。它被称为u
。 u
的构造函数被调用,将一个字符串作为参数传递给它。 university
的“参数化”构造函数被调用。构造函数的成员初始化部分只不过是一个简单的列表:这里是我的 class 成员,这里是它们各自构造函数的参数。 Abracadabra:它们是构造出来的。
student() {
如果构造函数没有成员初始化部分,或者没有在初始化部分列出对象的成员,则会调用相应的 class 成员的默认构造函数。
就是这样,就是这样:你的 class *这里 class 被称为 student
) 有成员,class 的构造函数显式初始化它们,为 class 成员调用相应的构造函数。如果任何 class 成员未在初始化部分中列出,则调用其默认构造函数,如果 class 成员没有默认构造函数,则生成的代码为 ill-formed 并且不会编译。
成员没有在构造函数的主体中初始化。它们在构造函数主体执行之前被初始化。当你写:
class student{
private:
university u;
public:
student() {
u = university("ABC");
}
};
则u = unisversizy("ABC");
不是初始化。由于您没有为 u
成员提供初始化程序,它将通过调用其默认构造函数进行初始化。然后在构造函数中 university("ABC")
通过调用另一个构造函数创建另一个对象并将其分配给 u
.
PS:在我看来,“参数化构造函数”这个术语是一个非常具有误导性的术语。 “参数化构造函数”和教程中经常出现的默认构造函数之间的区别是错误的。默认构造函数是可以不带参数调用的构造函数,因此下面是默认构造函数(并且可以带参数调用):
struct foo {
foo(int x = 0) {} // a default constructor
// is this a parametrized constructor ?!?
};
案例一
这里我们考虑的情况是:
student() {
u = university("ABC"); //this is assignment not initialization
}
当你写道:
student s;
以上语句的效果如下:
- 调用 class
student
的默认构造函数 student::student()
。
- Before entering/executing 默认构造函数
student::student()
的主体,class [=23] 的默认构造函数 university::university()
=] 是 隐式调用 。结果,您得到输出:
default constructor of university is invoked
现在一旦 university::university()
的主体完全执行,默认 ctor student::student()
的主体的执行是 resumed.
在执行student::student()
的主体时遇到以下语句:
u = university("ABC");
这是一个赋值,而不是初始化。由于表达式 univerisity("ABC")
,使用 class university
的 参数化构造函数 创建了一个临时 university
对象,因此您得到输出:
parametrized constructor of university is invoked: ABC
- 上一步创建的临时文件赋值给数据成员
u
。
案例二
这里我们考虑的情况是:
student(): u(university("ABC")){
}
当你写道:
student s;
事情是这样的:
- 调用了 class
student
的默认构造函数。
- 在进入默认构造函数
student::student()
之前,参数化构造函数university::university(std::string)
的class university
被调用是因为你有表达式 university("ABC")
并且数据成员 u
被 初始化 。请注意,由于调用了参数化的 ctor,您将获得输出:
default constructor of university is invoked
- 现在,当参数化构造函数的主体完成时,class
student::student()
的默认构造函数主体的执行 student
恢复 .
备注
在您的示例的情况 2 中,您应该将 student():u(university("ABC")){}
更改为:
student(): u("ABC"){
}
以下节目
#include <iostream>
using namespace std;
class university{
private:
string uni;
public:
university(){
cout<<"default constructor of university is invoked"<<endl;
}
university(string u){
uni =u;
cout<<"parametrized constructor of university is invoked: "<<uni;
}
};
class student{
private:
university u;
public:
student() {
u = university("ABC");
}
};
int main()
{
student s;
return 0;
}
输出是:
default constructor of university is invoked
parametrized constructor of university is invoked: ABC
但是当更改 student class 的构造函数以使用如下初始化列表时:
student(): u(university("ABC")){
}
输出是:
parametrized constructor of university is invoked: ABC
我的问题是:
对于第二种情况,当编译器在 student class 的私有部分运行 university u
行时,它是否创建了 class 'university' 的对象 'u' 和为其分配内存地址,还是在初始化列表中创建对象?如果是前者,那为什么不调用默认构造函数呢?
对于第一种情况,我有同样的问题,对象是在哪里创建并分配内存位置的。
“分配内存”和“分配内存位置”与此处无关。您问的是如何构建作为另一个 class 成员的对象。试图在这里引入内存分配的主题只会使事情变得混乱。高级 C++ 技术允许“在同一位置”重复构造和销毁对象(通过 placement new 和显式析构函数调用)。实际内存位置和对象 constructions/destructions 完全无关紧要。它们彼此无关,如果您只是忘记有关内存位置的所有内容,而只关注对象构造和销毁的主题,这将很有帮助。说了这么多:
对象构造函数负责构造对象的所有成员。这是规则。没有例外。句号。
student(): u(university("ABC")){
这会奏效,但在令人困惑的成员中也会这样做。这阐明了以下事件顺序:构造临时 university
对象,然后 copy-constructs student
class 的实际成员,最后临时对象被销毁。这是不必要的,只会把水搅浑。使用更简单、现代的 C++ 语法,这应该是:
student(): u{"ABC"}{
这种更短、更直接的语法以简单、简洁的方式准确地描述了正在发生的事情:对象的构造函数构造了该对象的所有成员,即这里只有一个成员。它被称为u
。 u
的构造函数被调用,将一个字符串作为参数传递给它。 university
的“参数化”构造函数被调用。构造函数的成员初始化部分只不过是一个简单的列表:这里是我的 class 成员,这里是它们各自构造函数的参数。 Abracadabra:它们是构造出来的。
student() {
如果构造函数没有成员初始化部分,或者没有在初始化部分列出对象的成员,则会调用相应的 class 成员的默认构造函数。
就是这样,就是这样:你的 class *这里 class 被称为 student
) 有成员,class 的构造函数显式初始化它们,为 class 成员调用相应的构造函数。如果任何 class 成员未在初始化部分中列出,则调用其默认构造函数,如果 class 成员没有默认构造函数,则生成的代码为 ill-formed 并且不会编译。
成员没有在构造函数的主体中初始化。它们在构造函数主体执行之前被初始化。当你写:
class student{
private:
university u;
public:
student() {
u = university("ABC");
}
};
则u = unisversizy("ABC");
不是初始化。由于您没有为 u
成员提供初始化程序,它将通过调用其默认构造函数进行初始化。然后在构造函数中 university("ABC")
通过调用另一个构造函数创建另一个对象并将其分配给 u
.
PS:在我看来,“参数化构造函数”这个术语是一个非常具有误导性的术语。 “参数化构造函数”和教程中经常出现的默认构造函数之间的区别是错误的。默认构造函数是可以不带参数调用的构造函数,因此下面是默认构造函数(并且可以带参数调用):
struct foo {
foo(int x = 0) {} // a default constructor
// is this a parametrized constructor ?!?
};
案例一
这里我们考虑的情况是:
student() {
u = university("ABC"); //this is assignment not initialization
}
当你写道:
student s;
以上语句的效果如下:
- 调用 class
student
的默认构造函数student::student()
。 - Before entering/executing 默认构造函数
student::student()
的主体,class [=23] 的默认构造函数university::university()
=] 是 隐式调用 。结果,您得到输出:
default constructor of university is invoked
现在一旦
university::university()
的主体完全执行,默认 ctorstudent::student()
的主体的执行是 resumed.在执行
student::student()
的主体时遇到以下语句:
u = university("ABC");
这是一个赋值,而不是初始化。由于表达式 univerisity("ABC")
,使用 class university
的 参数化构造函数 创建了一个临时 university
对象,因此您得到输出:
parametrized constructor of university is invoked: ABC
- 上一步创建的临时文件赋值给数据成员
u
。
案例二
这里我们考虑的情况是:
student(): u(university("ABC")){
}
当你写道:
student s;
事情是这样的:
- 调用了 class
student
的默认构造函数。 - 在进入默认构造函数
student::student()
之前,参数化构造函数university::university(std::string)
的classuniversity
被调用是因为你有表达式university("ABC")
并且数据成员u
被 初始化 。请注意,由于调用了参数化的 ctor,您将获得输出:
default constructor of university is invoked
- 现在,当参数化构造函数的主体完成时,class
student::student()
的默认构造函数主体的执行student
恢复 .
备注
在您的示例的情况 2 中,您应该将 student():u(university("ABC")){}
更改为:
student(): u("ABC"){
}