构造函数的执行分两个阶段完成:
初始化阶段
- 醇>
正文执行阶段,由构造函数体内的所有语句组成。请注意,类型的数据成员始终在初始化阶段初始化,无论该成员是否在构造函数初始化列表中显式初始化。初始化发生在构造函数体的任何语句执行之前。
让我们考虑一种通过构造函数初始化 class student 实例的方法 -
Student(string &fn, string &ln, int i, int y = Freshman)
: first_name(fn)
, last_name(ln)
, id(i)
, year(y)
{}
这是另一种,但“低效”和“不优雅”的做法 -
Student(string &fn, string &ln, int i, int y = Freshman)
{
first_name = fn;
last_name = ln;
id = i;
year = y;
}
新代码中的此构造函数(上面的代码)分配类Student的成员。它没有明确初始化它们。是否存在显式初始值设定项,即使在执行构造函数之前,也会初始化first_name和last_name成员。此构造函数隐式使用默认字符串构造函数来初始化first_name和last_name成员。执行构造函数的主体时,first_name和last_name成员已具有值。这些值将被构造函数体内的赋值覆盖。
所以,这意味着当执行到达构造函数的左括号时,这就是条件 -
现在,很明显,赋值是在构造函数体中对四个变量中的每一个进行的。
我对这件事的理解是对的吗?我不知何故觉得我错过了什么。
此外,在使用初始化列表时,是默认构造函数(编译器为我们生成的构造函数),使用我们的参数调用并传递(在 string 的情况下)和初始化完成,如在“int id = i;”中,如果是id(i)??
PS:大部分报价均来自此链接 -
答案 0 :(得分:7)
您的理解大多是正确的,除非您必须初始化初始化中的const
成员,因为您无法分配给他们(因为他们是const
)构造函数的主体或其他任何地方。如果您尝试将const
成员保留为未初始化状态,则会出现编译错误。
是的,在初始化列表中,调用与您提供的参数匹配的对象的构造函数。如果没有参数(例如: blah()
),则调用默认构造函数。
另外,在某些情况下,绝对必须使用初始化列表(它不是可选),例如
const
名成员答案 1 :(得分:1)
你没有说你的Student
类是如何定义的,但你可能会对一件事情感到困惑:在你的第二个“不优雅”的版本中,first_name
不一定是一个常量字符串 - 相反,fn
是对const字符串的引用,您将的值分配给您的成员变量first_name
。
现在,转到初始化列表:这些的全部内容是你指定成员对象的哪些构造函数被调用。如果没有列表,则所有成员对象都会调用其默认构造函数(或者更准确地说,它们是默认初始化的)。但是,您在初始化列表中提到的任何对象都将 构造函数(或更确切地说是“初始化程序”)称为,而不是。
初始化列表不仅仅是装饰。这是必不可少的,因为成员对象和子对象甚至可能不是默认构造的,因此必须提供初始化程序 。 const成员实际上是一个非常好的例子:
struct Foo
{
const int n;
Foo(); // error! What is n?
Foo(int m) : n(m) { } // OK
};
这是另一个例子,这次是从没有默认构造函数的基类派生的:
struct Bar : Foo
{
Bar(); // error! How to initialize Foo?
Bar() : Foo(5) { } // OK, now Bar::n == 5
};
答案 2 :(得分:1)
此外,在使用初始化列表时,是默认的构造函数(编译器为我们制作的),使用我们的参数调用并传递(如果是字符串),并在“int id = i;”中完成初始化,以防万一id(i)??
首先,默认构造函数不一定是“编译器为我们制作的”。它们只是没有参数的构造函数,例如Student()
。有时编译器会自动生成一个,例如int
,有时必须编写,就像std::string
一样。
考虑它的简单方法是:如果存在初始值设定项,则调用相应的构造函数。因此,假设first_name
为std::string
,则初始化程序first_name(fn)
会使first_name
结构std::string::string(const std::string&)
,并将fn
作为参数传递。如果初始值设定项未使用,则first_name
在执行std::string::string()
代码之前使用{ ... }
构建,然后在您编写first_name = fn;
时生成std::string::operator =(const std::string&)
在致电fn
时,将{{1}}作为参数传递。
最后,关于初始化器的重要一点是,它们按照成员在类中声明的顺序执行,不按照在构造函数中编写它们的顺序执行。此外,基类构造函数的初始化程序在成员初始化之前发生。