C++之类的构造函数初始化列表
下面给出代码,体会一下构造函数有无初始化列表的区别
#include<iostream> using namespace std; class Student{ private: char* m_name; int m_age; float m_score; public: Student(char* name,int age,float score); void show(); } /*不使用初始化列表,需要在函数体内完成赋值 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){ //TODO } Student::show(){ cout<<m_name<<"age:"<<m_age<<",score:"<<m_score<<endl; } int main() { Student stu("Ming",24,98); stu.show(); Student *pstu= new Student("xu",28,89); pstu->show(); return 0; }
使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便,尤其是成员变量较多时,这种写法非常简单明了。初始化列表还可以对部分变量进行初始化。
Student::Student(char *name, int age, float score): m_name(name){ m_age = age; m_score = score; }
注意,成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关。请看代码:
#include <iostream> using namespace std; class Demo{ private: int m_a; int m_b; public: Demo(int b); void show(); }; Demo::Demo(int b): m_b(b), m_a(m_b){ } void Demo::show(){ cout<<m_a<<", "<<m_b<<endl; } int main(){ Demo obj(100); obj.show(); return 0; }
运行结果:
2130567168, 100
在初始化列表中,我们将 m_b 放在了 m_a 的前面,看起来是先给 m_b 赋值,再给 m_a 赋值,其实不然!成员变量的赋值顺序由它们在类中的声明顺序决定,在 Demo 类中,我们先声明的 m_a,再声明的 m_b,所以构造函数和下面的代码等价:
Demo::Demo(int b): m_b(b), m_a(m_b){ m_a = m_b; m_b = b; }
给 m_a 赋值时,m_b 还未被初始化,它的值是不确定的,所以输出的 m_a 的值是一个奇怪的数字;给 m_a 赋值完成后才给 m_b 赋值,此时 m_b 的值才是 100。
初始化 const 成员变量
构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。例如 VS/VC 不支持变长数组(数组长度不能是变量),我们自己定义了一个 VLA 类,用于模拟变长数组,请看下面的代码:
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 类包含了两个成员变量,m_len 和 m_arr 指针,需要注意的是 m_len 加了 const 修饰,只能使用初始化列表的方式赋值,如果写作下面的形式是错误的:
class VLA{ private: const int m_len; int *m_arr; public: VLA(int len); }; VLA::VLA(int len){ m_len = len; m_arr = new int[len]; }
const用于类中成员变量时,将类成员变为只读属性(只读:不能出现在“=”的左边,但在类中仍可以用一个指针来修改其值。) 所以不可以直接在类的构造函数中初始化const 的成员。
那如果就想更改const成员变量呢,只能通过指针去改,如增加一个函数:
public: void setlen(int len){ int *plen=(int *)&m_len; *plen=len; }