补充
- 基本类型初始化、const类型初始化、引用初始化等等
- 在第9章中提到的不同存储类型变量的初始化
引用的初始化
必须在声明引用时将其初始化,而不能像指针那样,先声明,再赋值。引用更接近与const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就一直效忠于它。也就是说:
int & rodents = rats;
实际上是下述代码的伪装表示
int * const pr = &rats
类对象的初始化
构造函数
由于类对象数据部分的访问状态是私有的,因此程序不能直接访问数据成员,只能通过成员函数来访问数据成员。需要设计合适的成员函数才可以成功的将对象初始化。C++提供了一个特殊的成员函数——类构造函数,专门用于构造新对象,将值赋给新对象的数据成员。更准确的说,C++为这些成员函数提供了名称和使用语法,而程序员需要提供方法定义。构造函数名称与类名相同,且没有声明类型(没有返回值但没有被声明为void类型)。
C++提供了两种使用构造函数来初始化对象的方法。第一种方法是显式的调用构造函数:
Stock food = Stock("World Cabbage", 250, 1.25);
另一种方式是隐式的调用构造函数:
Stock garment("Furry Mason", 50, 2.5);
其与下面的显示调用等价:
Stock garment = Stock("Furry Mason", 50, 2.5);
每次创建对象(甚至使用new动态分配内存时),C++都使用类构造函数。下面是将构造函数与new一起使用的方法:
Stock *pstock = new Stock("Electroshock Games", 18, 19.0);
此时被创建的对象没有名称,但可使用指针来管理对象。
构造函数的使用方式不同于其他类方法,因为在构造函数构造出对象之前,对象是不存在的,因此构造函数被用来创建对象,而不能通过对象来调用。
默认构造函数
默认构造函数是在未提供显式初始值时,用来创建对象的构造函数。也就是说,它用于下面这种声明的构造函数:
Stock fluffy_the_cat;
当且仅当没有定义任何构造函数时,编译器才提供默认构造函数。为类定义了构造函数后,就必须为其提供默认构造函数,否则仅提供了非默认构造函数而没有提供默认构造函数,将无法创建不显式初始化的对象。
定义默认构造函数的方式有两种,一种是给已有构造函数的所有参数提供默认值,另一种方式是通过函数重载来定义另一个没有参数的构造函数,但不要同时采用这两种方式,因为只能有一个默认构造函数。使用上述任何一种方式创建了默认构造函数后,便可以声明对象变量而不对其进行初始化。
总的来说,自定义构造函数有如下两种方式,可任选一种:
- 创建两个构造函数,一个没有参数,但在其内部对类成员进行初始化(隐式初始化),一个有参数,在其内部用参数为类成员进行赋值(显式初始化);
- 只创建一个构造函数,这个构造函数有参数,但为每个参数均提供了默认值。
类的列表初始化
提供与某个构造函数的参数列表匹配的内容,并用大括号将它们括起来,可以实现类的列表初始化。
Stock hot_tip = {"Derivatives Plus Plus", 100, 45.0};
Stock jock {"Sport Age Storage, Inc"};
Stock temp {};
在前两个声明中,用大括号括起来的列表与下面的构造函数匹配:
Stock::Stock(const std::string & co, long n = 0, double pr = 0.0);
因此,将使用默认构造函数来创建这两个对象。创建对象jock时,第二个和第三个参数将为默认值0和0.0。第三个声明与默认构造函数匹配,因此将使用该构造函数创建对象temp。
需要注意的是,只有在参数列表中提供默认值的构造函数,才会与仅提供部分参数的类对象列表初始化语句相匹配;否则,仅提供部分参数的列表初始化即不与隐式初始化的构造函数相匹配,也不与要求提供全部参数的构造函数相匹配。
对象数组的初始化
声明对象数组的方法与声明标准类型数组相同:
Stock mystuff[4];
对于对象数组中的每个元素(mystuff[0]、mystuff[1]等),都是Stock对象,可以使用Stock方法,也可以使用构造函数来初始化数组元素。但必须为每个元素调用构造函数:
Stock stocks[4] = {
Stock("NanoSmart", 12.5, 20),
Stock("Boffo Objects", 200, 2.0),
Stock("Monolithic Obelisks", 130, 3.25),
Stock("Fleep Enterprises", 60, 6.5)
};
这里的代码使用标准格式对数组进行初始化:用括号括起来的、以逗号分隔的值列表。其中,每次构造函数调用表示一个值。如果类包含多个构造函数,则可以对不同的元素使用不同的构造函数:
Stock stocks[10] = {
Stock("NanoSmart", 12.5, 20),
Stock(),
Stock("Monolithic Obelisks", 130, 3.25),
};
上述代码使用构造函数Stock(const string & co, long n, double pr)初始化stocks[0]和stocks[2],使用构造函数Stock()初始化stocks[1]。由于该声明只初始化了数组的部分元素,因此余下的7个元素将使用默认构造函数进行初始化。
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。因此,要创建对象数组,则这个类必须有默认的构造函数。
注意成员初始化列表语法与类对象列表初始化的区别,成员初始化列表为仅在构造函数中可用的对类数据成员进行初始化的一种语法,是构造函数初始化对象数据成员的一种内部实现方式,而类对象列表初始化则是由外部通过类的构造函数传入对象数据成员初值的方式。