构造函数对成员变量的初始化

  构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用初始化列表。

class Student{
private:
  char *m_name;
  int m_age;
  float m_score;
public:
  //声明构造函数
  Student(char *name, int age, float score);
};


//对成员一一赋值
Student::Student(char *name, int age, float score){
  m_name = name;
  m_age = age;
  m_score = score;
}

 

//采用初始化列表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){

}

 

使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便,尤其是成员变量较多时,这种写法非常简单明了。

构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。

class VLA{
private:
  const int m_len;
  int *m_arr;
public:
  VLA(int len);
};

//必须使用初始化列表来初始化 m_len
VLA::VLA(int len): m_len(len){
  m_arr = new int[len];
}

//以下写法是错误的

VLA::VLA(int len){
m_len = len;
m_arr = new int[len];
}

VLA 类包含了两个成员变量,m_len 和 m_arr 指针,需要注意的是 m_len 加了 const 修饰,只能使用初始化列表的方式赋值。

 

1、初始化列表(Initialization List)
  初始化列表是在构造函数的参数列表后,使用冒号 : 开始的成员初始化部分。

  特点
  直接初始化:

    成员变量在进入构造函数体之前就已经被初始化。

    对于类类型的成员变量,直接调用其构造函数。

  性能优势:

    避免不必要的默认构造和赋值操作,效率更高。

  必须使用初始化列表的情况:

    常量成员(const):必须在初始化列表中初始化。

    引用成员(&):必须在初始化列表中初始化。

    没有默认构造函数的类类型成员:必须在初始化列表中初始化。

  初始化顺序:

    成员变量的初始化顺序与它们在类中声明的顺序一致,与初始化列表中的顺序无关。

2.、构造函数体内赋值(Assignment in Constructor Body)
  构造函数体内赋值是在构造函数体内通过赋值操作初始化成员变量。

  特点
  先默认构造,再赋值:

    对于类类型的成员变量,先调用默认构造函数,再调用赋值操作符。

    对于内置类型(如 int、double),直接赋值。

  性能劣势:

    对于类类型成员变量,会多一次默认构造和赋值操作,效率较低。

  适用场景:

    适用于内置类型或简单的类类型成员变量。

    不适用于常量成员、引用成员或没有默认构造函数的类类型成员。


3、区别对比
特性         初始化列表                         构造函数体内赋值
初始化时机     在进入构造函数体之前完成初始化             在构造函数体内通过赋值完成初始化
性能 更高      (直接初始化,避免额外操作)             较低(可能涉及默认构造和赋值)
适用场景      所有类型成员变量                   仅适用于内置类型或简单类类型
必须使用的情况   常量成员、引用成员、无默认构造函数的类类型成员     不适用
初始化顺序     与成员变量声明顺序一致                 与赋值顺序一致

4、必须使用初始化列表的情况

常量成员:

一般直接在类声明中定义内联函数。

class MyClass {
public:
  MyClass(int a) : x(a) {} // 必须使用初始化列表
private:
  const int x;
};

 引用成员:

class MyClass {
public:
  MyClass(int& a) : x(a) {} // 必须使用初始化列表
private:
  int& x;
};

 没有默认构造函数的类类型成员:

class NoDefaultConstructor {
public:
NoDefaultConstructor(int a) {}
};

class MyClass {
public:
MyClass(int a) : obj(a) {} // 必须使用初始化列表
private:
NoDefaultConstructor obj;
};

5、总结

  初始化列表:

    更高效,直接初始化成员变量。

    适用于所有类型成员变量,尤其是常量成员、引用成员和没有默认构造函数的类类型成员。

  构造函数体内赋值:

    适用于内置类型或简单的类类型成员变量。

    性能较低,不推荐用于复杂类类型成员变量。

    在实际开发中,优先使用初始化列表,除非有特殊需求需要在构造函数体内进行复杂的逻辑操作。

 

posted @ 2025-03-05 17:34  孤情剑客  阅读(315)  评论(0)    收藏  举报