第八章(第一部分)
A.构造函数和析构函数
一、构造函数Constructor的特征
(1) 语法SYNTAX
- 构造函数的函数名与类名相同;
- 构造函数没有返回值;
- 当新对象被创建时,构造函数会被自动调用。
class ClassName{
public:
ClassName(Parameter List)
{
}
}
下面是几个构造函数实例:
class Playing Card{
public:
//构造函数,创建新的playing card
PlayingCard(Suits is,int ir)
{
//函数体中的语句可以是普通函数的任意语句,也可以对类成员任意赋值、调用。
suitValue=is;
rankValue=ir;
}
...
private:
Suits suitValue;
int rankValue;
}
(2) 初始化器Initializer
构造函数可以使用初始化器Initializer来初始化,更加便利。
初始化器的语法是紧挨在参数列表圆括号之后一个冒号:,在函数体花括号{}之前成员+(形参),以逗号相连。
值得注意的是,初始化器只能初始化一些普通成员,有些成员是不能初始化的
举例:
class PlayingCard{
public:
PlayingCard(Suits is,int ir):suitValue(is),rankValue(ir)
{}
...
private:
Suits suitValue;
int rankValue;
}
(3) 默认构造函数Default Constructor
没有参数的构造函数是默认构造函数。一个类只能有一个默认构造函数。
ClassName::ClassName()
{}
用户可以自定义构造函数,如果没有写任何自定义构造函数,那么系统就会自动生成一个空的默认构造函数。注意:如果用户自定义了一个[非默认构造函数](## 构造函数的重载Overloaded Constructors),但是没有自定义一个默认构造函数,此时系统并不会自动生成默认构造函数!!
例如一个类定义如下:
class PlayingCard{
public:
PlayingCard(Suits is,int ir)//只定义了带两个参数的构造函数
{
suitValue=is;
rankValue=ir;
}
}
如果调用时:
PlayingCard cardone();//非法,无法调用默认参数
PlayingCard cardtwo;//非法,无法调用默认参数
PlayingCard cardthree(PlayingCard::Cube,5)//唯一合法创建构造函数方式
默认构造函数的特点是没有参数、没有语句。
在创建对象时,如果括号里没有参数,或者没有带括号,就会调用默认参数
(4) 构造函数的重载Overloaded Constructors
重载的构造函数相互之间以参数列表的数量和类型相互区分
class PlayingCard{
public:
PlayingCard()//默认构造函数
{
suitValue=Diamond;
rankValue=1;
}
PlayingCard(Suits is,int ir)//带两个参数的构造函数
{
suitValue=is;
rankValue=ir;
}
}
其相应的创建对象实例为:
PlayingCard cardOne;//调用默认构造函数
//默认构造函数调用时是不需要带括号的
PlayingCard cardThree(PlayingCard::Club,6);//调用带两个参数的构造函数
(5) 默认参数的构造函数Constructor with Default Parameters
与普通函数的默认参数规则一致,无二义性原则。
二、析构函数Destructor的特征
(1) 语法SYNTAX
- 函数名为“~+类名”;
- 没有返回值;
- 参数列表为空
- 不能被重载
- 无论何时,当一个对象的生命终结时,析构函数会被自动调用。
class ClassName{
public:
~ClassName(){}
}
(2) 默认析构函数
如果用户没有写析构函数,系统会生成默认析构函数。
ClassName::~ClassName()
{}
三、成员的生命周期和构造函数、析构函数的调用顺序
成员的生命采取栈的形式,先被构造的先被析构,后被构造的后被析构。
例如;
#include<iostream>
using namespace std;
class Trace {
public:
//Constructor
Trace(string);
//Destructor
~ Trace();
private:
string text;
};
void procedureA();
void procedureB(int x);
int main() {
procedureA();
}
Trace::Trace(string t): text(t) {
cout << "entering " << text << endl;
}
Trace::~Trace() {
cout << "exiting " << text << endl;
}
void procedureA() {
Trace dummy("procedure A");
procedureB(7);
}
void procedureB(int x) {
Trace dummy("procedure B");
if (x < 5) {
Trace aaa("true case in Procedure B");
} else {
Trace bbb("false cases in Procedure B");
}
}
示例结果:
解释:先生成了dummy(“procedure A”),然后生成了dummy(“false cases in Procedure B”),再生成了bbb(“procedure B”)。其消亡顺序与生成顺序相反。
B.对象数组
对象数组,是在内存区中开辟的用于储存一定数量的相同类的对象的连续空间
建立对象数组时,分为两个步骤:
- 为数组本身分配内存;
- 为对象数组的每一个元素(对象)分配内存
(1) 语法SYNTAX:
ClassName ArrayName[const int Expression];
(2) 对象数组的初始化:
默认构造函数初始化:
如果类拥有默认构造函数成员,则可以简易地用以下形式初始化一个对象数组
PlayingCard cardArray[52];
非默认构造函数的初始化:
如果类内没有默认构造函数成员,则对象数组的创建必须以如下格式完成:
ClassName object[const int num]{
ClassName(..., ...),//括号内参数列表
ClassName(..., ...),
...
}
例如:
PlayingCard cardArray[2]={
PlayingCard(PlayingCard::Heart,1),
PlayingCard(PlayingCard::Club,2)
};