2009-05-29 97 views

回答

202

对于POD班级成员,它没有区别,这只是一个风格问题。对于类成员来说,它避免了对默认构造函数的不必要的调用。试想一下:

class A 
{ 
public: 
    A() { x = 0; } 
    A(int x_) { x = x_; } 
    int x; 
}; 

class B 
{ 
public: 
    B() 
    { 
     a.x = 3; 
    } 
private: 
    A a; 
}; 

在这种情况下,B构造函数将调用默认的构造函数为A,然后初始化a.x到3.更好的办法将是B的构造函数直接调用A的构造函数初始化列表:

B() 
    : a(3) 
{ 
} 

这只会叫AA(int)构造函数,而不是它的默认构造函数。在这个例子中,差异是可以忽略的,但想象一下,如果你想让A的默认构造函数做的更多,例如分配内存或打开文件。你不希望这样做不必要。

此外,如果一个类没有默认构造函数,或者你有一个const成员变量,你必须使用初始化值列表:

class A 
{ 
public: 
    A(int x_) { x = x_; } 
    int x; 
} 

class B 
{ 
public: 
    B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list; 
    {     // it is an error not to do so 
    } 
private: 
    A a; 
    const int y; 
}; 
+0

类成员这是类可以POD,太 – 2013-03-21 15:24:01

+1

一绝,也是一个参考 – 4pie0 2014-05-06 12:38:52

+1

重要的情况下,为什么不使用“A(3);”或“a = A(3);”在B的默认构造函数体中? – Sergey 2015-03-06 10:07:49

34
从上述性能的原因

除此之外,如果你的类存储对作为构造函数参数传递的对象的引用,或者你的类有const变量,那么你除了使用初始值设定项列表外没有其他选择。

6

除了性能问题,还有一个非常重要的问题,我称之为代码可维护性和可扩展性。

如果T是POD,并且您开始更喜欢初始化列表,那么如果一次T将更改为非POD类型,则不需要在初始化期间更改任何内容以避免不必要的构造函数调用,因为它已经过优化。

如果类型T确实有默认构造函数和一个或多个用户定义的构造函数,并且您决定删除或隐藏默认构造函数,那么如果使用初始化列表,则不需要更新代码,如果您的用户 - 定义的构造函数,因为它们已经被正确地实现。

同样的,const的成员或引用成员,假设如下初始T被定义为:

struct T 
{ 
    T() { a = 5; } 
private: 
    int a; 
}; 

接下来,你决定来限定为const,如果你想使用初始化列表从一开始,那么这是一个单行的变化,但具有T标准同上,也需要挖掘构造函数定义删除任务:

struct T 
{ 
    T() : a(5) {} // 2. that requires changes here too 
private: 
    const int a; // 1. one line change 
}; 

这不是一个秘密,维护更容易和更不容易出错,如果代码是不是由一个“代码monke写的y“,而是由一位工程师根据对他正在做的事情的深入考虑作出决定。

4

在构造函数的主体运行之前,调用其父类的所有构造函数,然后调用它的字段。默认情况下,调用无参数构造函数。初始化列表允许您选择调用哪个构造函数以及构造函数接收哪些参数。

如果您有一个引用或常量字段,或者所用的某个类没有默认构造函数,则必须使用初始化列表。

2
// Without Initializer List 
class MyClass { 
    Type variable; 
public: 
    MyClass(Type a) { // Assume that Type is an already 
        // declared class and it has appropriate 
        // constructors and operators 
     variable = a; 
    } 
}; 

这里编译器符合以下步骤创建类型的对象MyClass的
1.键入的构造首先被调用为“A”。
2.“类型”的赋值运算符被称为内部MyClass的()构造的主体分配

variable = a; 
  • 然后终于的“类型”析构函数被称为为“a”,因为它超出了范围。

    现在考虑MyClass的(相同的代码)构造函数初始化列表

    // With Initializer List 
    class MyClass { 
    Type variable; 
    public: 
    MyClass(Type a):variable(a) { // Assume that Type is an already 
           // declared class and it has appropriate 
           // constructors and operators 
    } 
    }; 
    

    随着初始化列表,下面的步骤之后编译:

    1. “类型”类的拷贝构造调用初始化:variable(a)。初始化列表中的参数用于直接复制构造“变量”。
    2. “类型”的析构函数因为超出范围而被称为“a”。这里
  • 10
    1. 基类的初始化

    一个使用未在答案中提到的构造函数初始化列表重要的原因是基类的初始化。

    根据构建顺序,基类应该在子类之前构建。没有构造函数初始化列表,如果你的基类有默认的构造函数,在进入子类的构造函数之前调用它,这是可能的。但是,如果你的基类只有参数化构造函数,那么你必须使用构造函数初始化列表来确保你的基类在子类之前被初始化。

  • 子对象只具有参数化的构造

  • 效率

  • 使用构造函数初始化列表初始化的,您的数据成员初始化在代码中需要的确切状态,而不是首先将它们初始化为默认状态&然后将其状态更改为您需要的状态你的代码。

  • 初始化非静态常量数据成员
  • 如果你的类的非静态常量数据成员有默认构造函数&你不使用构造函数初始化列表,您将无法将它们初始化为预期状态,因为它们将被初始化为默认状态。

    的基准数据成员
  • 初始化
  • 参考数据成员必须作为参考,不能只是声明&后初始化时编译器进入构造函数intialized。这只有在构造函数初始化列表中才有可能。

    0

    语法:

    class Sample 
        { 
        public: 
         int Sam_x; 
         int Sam_y; 
    
        Sample(): Sam_x(1), Sam_y(2)  /* Classname: Initialization List */ 
        { 
          // Constructor body 
        } 
        }; 
    

    初始化列表的极品:

    class Sample 
    { 
        public: 
         int Sam_x; 
         int Sam_y; 
    
        Sample()  */* Object and variables are created - i.e.:declaration of variables */* 
        { // Constructor body starts 
    
         Sam_x = 1;  */* Defining a value to the variable */* 
         Sam_y = 2; 
    
        } // Constructor body ends 
        }; 
    
    在上面的程序

    ,当执行类的构造函数,和Sam_y创建Sam_x。然后在构造函数体中,定义这些成员数据变量。

    用例:在一类

    在C

    1. CONST和参考变量,变量必须被创建期间定义。在C++中使用相同的方式,我们必须使用初始化列表在对象创建期间初始化Const和引用变量。如果我们在创建对象之后(内部构造函数体)进行初始化,我们会得到编译时错误。

    2. 会员的Sample1的物体(基体),其不具有默认的构造

      class Sample1 
      { 
          int i; 
          public: 
          Sample1 (int temp) 
          { 
           i = temp; 
          } 
      }; 
      
          // Class Sample2 contains object of Sample1 
      class Sample2 
      { 
          Sample1 a; 
          public: 
          Sample2 (int x): a(x)  /* Initializer list must be used */ 
          { 
      
          } 
      }; 
      

    虽然这将在内部调用派生类的派生类创建对象类构造函数并调用基类构造函数(默认)。如果基类没有默认构造函数,用户将得到编译时错误。为了避免,我们必须具有

    1. Default constructor of Sample1 class 
    2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program) 
    
  • 一类的

    类构造函数的参数名称和数据部件是相同的:

    class Sample3 { 
        int i;   /* Member variable name : i */ 
        public: 
        Sample3 (int i) /* Local variable name : i */ 
        { 
         i = i; 
         print(i); /* Local variable: Prints the correct value which we passed in constructor */ 
        } 
        int getI() const 
        { 
         print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/ 
         return i; 
        } 
    }; 
    
  • 大家都知道,具有最高优先级的局部变量然后是全局变量,如果两个变量具有相同的名称。在这种情况下,程序会考虑“i”值(左右变量)。即:i = i}作为Sample3()构造函数中的局部变量,并且Class成员变量(i)被覆盖。为了避免,我们必须使用

    1. Initialization list 
        2. this operator. 
    
    相关问题