常见问题
Q1. 下列关于构造函数的描述中,错误的是( )
A. 构造函数可以设置默认的参数
B. 构造函数在定义类对象时自动执行
C. 构造函数可以是内联函数
D. 构造函数不可以重载
Q2. 下列代码中a、b的各个成员变量值是多少?
1 class Student 2 { 3 public: 4 Student() {} 5 void show(); 6 private: 7 string name; 8 int number; 9 int score; 10 }; 11 Student a; 12 int main() 13 { 14 Student b; 15 }
Q3. 运行下面的C++代码,其输出结果是什么?
1 #include <iostream> 2 using namespace std; 3 class A 4 { 5 private: 6 int i; 7 int j; 8 public: 9 A() : j(0), i(j+2) {} 10 void print() 11 { 12 cout << "i: " << i << ", j: " << j << endl; 13 } 14 }; 15 int main() 16 { 17 A a; 18 a.print(); 19 return 0; 20 }
构造函数、成员初始化列表
1. 构造函数
构造函数是特殊的成员函数,与其他成员函数不同,构造函数和类同名,而且没有返回类型。一个类可以有多个构造函数,每个构造函数必须有与其他构造函数不同数目或类型的形参。
2. 默认构造函数
如果没有为一个类显式定义任何构造函数,编译器将自动为这个类生成默认构造函数。默认构造函数是不带参数的构造函数,或所有的形参都有默认实参的构造函数。
若使用编译器自动生成的默认构造函数(或自己定义一个未进行任何操作的默认构造函数),则类中的每个成员,例用与初始化变量相同的规则来进行初始化。
(1) 类成员:运行该类型的默认构造函数来初始化。
(2) 内置或复合类型的成员初始值依赖于对象的作用域:在局部作用域中这些成员不被初始化,而在全局作用域中它们被初始化为0。
实际上,如果定义了其他构造函数,则提供一个默认构造函数几乎总是对的。
3. 成员初始化列表
在冒号和花括号之间的代码称为构造函数的初始化列表。构造函数的初始化列表为类的一个或多个数据成员指定初值。它跟在构造函数的形参表之后,以冒号开始。构造函数的初始化式是一系列成员名,每个成员后面是括在圆括号中的初始值。多个成员的初始化用逗号分隔。
在C++中,成员变量的初始化顺序与变量在类型中的声明顺序相同,而与它在构造函数的初始化列表中的顺序无关。
省略初始化列表在构造函数的函数体内对数据成员赋值是合法的。从概念上讲,可以认为构造函数分两个阶段执行:
(1) 初始化阶段;
(2) 普通计算阶段。计算阶段由构造函数体中的所有语句组成。
不管成员函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化(调用默认构造函数初始化,若没有默认构造函数,则编译错误),内置和复合类型的成员,只对定义在全局作用域中的对象才初始化,定义在局部作用域中的对象包含的内置(如int等类型)和复合(如数据、指针等类型)类型的成员没有初始化。
因为内置类型的成员不进行隐式初始化,所以对这些成员是进行初始化还是赋值无关紧要。但对于类类型的数据成员若未在初始化列表显式初始化,而是在函数体里赋值,则相当于先调用类的默认构造函数进行初始化,再在函数体中赋值,故相比于直接利用初始化列表,效率较低。
必须使用成员初始化列表的情况如下:
有些数据成员必须在构造函数的初始化列表中进行初始化。对于这样的成员,在构造函数体内对它们赋值是不起作用的。没有默认构造函数的类类型的成员,以及const类型的成员变量和引用类型的成员变量,都必须在构造函数初始化列表中进行初始化。