2011-09-10 82 views
2

执行分两个阶段进行:执行在C构造++构造的

  1. 初始化阶段

  2. 机构执行其由构造的主体内的所有语句的相位。请注意,类类型的数据成员始终在初始化阶段初始化,而不管成员是否在构造函数初始化程序列表中显式初始化。初始化发生在构造函数主体的任何语句执行之前。

让我们考虑由构造初始化类学生的一个实例的方式 -

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成员已经具有值。这些值被构造函数体内的赋值覆盖。

所以,这意味着通过执行到达构造的开口支架的时候,这是条件 -

  • “如first_name”,这是一个是通过调用初始化默认字符串构造函数(编译器'生成')。
  • “姓氏”,这是一个字符串是通过调用默认字符串的构造函数(一个“使得”,其编译器)初始化。
  • 'id',这是一个整数未初始化
  • 'year',这是一个整数未初始化

而现在,很明显,在分配完成每四个变量,在构造函数体。

我对这件事的理解是对的吗?我不知何故觉得我失去了一些东西。

而且在使用的初始化列表,是默认的构造函数(其中一个编译器使我们),被称为与我们的参数传递(在的情况下)和初始化完成,如“INT id = i;“在id(i)的情况下?

PS:大部分的报价都是从这个链接 -

http://www.bogotobogo.com/cplusplus/constructor.php

回答

7

你的理解是正确的大部分,但你必须的初始化器初始化const成员,因为你不能分配给他们(因为它们是const)在构造函数的主体或其他任何地方。如果您尝试将const成员保留为未初始化状态,您将收到编译错误。

是的,在初始化列表中,调用与您给它的参数相匹配的对象的构造函数。如果没有参数(例如: blah()),则调用默认构造函数。

的方法,另外,也有一些情况下,您绝对必须使用初始化器列表(它不可选),如

  • 当类有const成员
  • 当类是不带默认构造函数的类的直接子女
  • 当班级有参考成员
+0

@ Seth,谢谢你的回复。如果我删除** const **关键字(为了简化情况),您可以评论一下这个场景吗? – jsp99

+0

@Appy那么你在所有账户上都是正确的。 –

+0

@Appy进行了更新:您不能让'const'成员未初始化。 +1给Kerrek。 –

1

你不是说你的类是如何定义的,但是你可能会对一件事感到困惑:在你的第二个“不雅”版本中,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 
}; 
+0

+1,不知道'const'成员不能被排除在初始化列表之外。 –

1

而且在使用的初始化列表,是默认的构造函数(编译器为我们编写的),调用并传入参数(在字符串的情况下),并在id(i)的情况下进行初始化,如“int id = i;”。

首先,默认的构造函数不一定是“编译器为我们编写的”。它们只是没有参数的构造函数,例如Student()。有时编译器自动生成一个,如int,有时必须写入,如std::string

想到这个问题的简单方法是:如果存在一个初始值设定项,则调用相应的构造函数。因此,假设first_namestd::string,那么初始化程序first_name(fn)的结果first_name变得与std::string::string(const std::string&)构建,通过fn作为参数。如果初始化是使用,然后first_namestd::string::string()构造{ ... }代码执行之前,那么当你写first_name = fn;,这导致对std::string::operator =(const std::string&)通话,传递fn作为参数。

最后,实现有关初始化最重要的事情是,他们在成员在类中声明,在你写他们在构造函数中,为了不的顺序执行。此外,基类构造函数的初始化器在成员初始化之前发生。

+0

谢谢迈克:) ...但“id(我)”怎么样。它是否使编译器(或CPU)通过与语句“int id = i;”相同的例程? – jsp99

+0

@快乐不完全。更像'int id(i)',有一​​点区别。 –

+0

“困惑”!你能解释一下我的区别吗? THanks .. :) – jsp99