构造函数
- 编译器会在每次类里的数据成员被定义出来的时候调用适当的函数加以处理,去初始化类对象里的数据成员,这种我们提供的一个或者多个特别的初始化函数就叫做构造函数;
- 构造函数的名称必须和类的名称相同;
- 语法规定:构造函数没有返回类型,所以构造函数的函数体没有return语句,构造函数也不返回任何值,它可以被重载。
class Triangular{
public:
//...
private:
int _length;//元素个数
int _beg_pos;//起始位置
int _next;//下一个迭代目标
Class Triangular{
public:
//一组重载的构造函数
Triangular();//默认的构造函数
Triangular(int len);
Triangular(int len,int beg_pos);
//...
};
Triangular t; //编译器自动根据获得的参数挑选应该被调用的构造函数
//编译器会对t应用默认的构造函数
Triangular t2(10,3);
//编译器会调用带两个参数的构造函数
//括号内的值会被视为传给构造函数的参数
Triangular t3=8;
//相当于Triangular t3(8);
//编译器会调用带一个参数的构造函数
Triangular t5(); //错误
Triangular t5; //ok
默认的构造函数
最简单的构造函数就是默认的构造函数,它不需要任何参数,意味着:
- 它不接受任何参数;
//默认的构造函数的定义方式1
//类主体外定义构造函数((注意这时就不要在右大括号后加;了)
Triangular::Triangular()
{
_length=1;
_beg_pos=1;
_next=0;
}
- 它为每个参数提供了默认值(常见):
class Triangular{
public:
Triangular(int len=1,int bp=1);//声明默认的构造函数
//...
};
Triangular::Triangular(int len,int bp)
{
//数列长度和起始位置都必须≥1!
_length=len>0 ? len:1;
_beg_pos=bp>0 ? bp:1;
_next=_beg_pos-1;//数组的逻辑序列和物理序列相差1
}
//使用构造函数来初始化数据成员
Triangular tri1;//Triangular::Triangular(1,1);
Triangular tri2(12);//Triangular::Triangular(12,1);
Tirangular tri3(8,3);//Triangular::Triangular(8,3);
成员初始化列表
构造函数定义的第二种初始化语法即成员初始化列表:
Triangular::Triangular(const Triangular &rhs)
: _length(rhs._length),//最后一个冒号前要Tab缩进,后面要加空格
_beg_pos(rhs.beg_pos),
_next(rhs.beg_pos-1)//成员初始化列表在单独的冒号后面,以逗号分隔
{};
//这个大括号里是空的
成员初始化列表主要用于将参数传给成员类对象的构造函数:
class Triangular{
public:
//...
private:
string _name;
int _next,_length,_beg_pos;
};
//以成员初始化列表的形式将_name的初值传给构造函数的形参
Triangular::Triangular(int len,int bp)
: _name("Triangular")
{
_length=len>0?len:1;
_beg_pos=bp>0?bp:1;
_next=_beg_pos-1;
}
析构函数
- 与构造函数对立的是析构函数,是用户自定义的一个类成员,主要用来释放在构造函数或类对象生命周期中分配的资源;
- class名称加上~前缀;
- 析构函数没有返回值,也没有任何参数;
- 由于析构函数参数列表是空的,所以不可能被重载。
class Matirx{
public:
Matirx(int row,int col)
:int _row(row),_col(col)
{
//构造函数在此进行数据成员的资源的分配
_pmat=new double[ row * col ];
}
~Matrix()//定义
{
//析构函数进行资源释放
delete[] _pmat;
}
private:
int _row,_col;
double* _pmat;
};
//应用
{
Matrix mat(4,4);
//构造函数
//...
//析构函数
}
- 编译器会在mat被定义出来的下一刻,自动应用Matrix构造函数;
- 析构函数是非必要的,了解何时需要定义析构函数而何时不需要是C++编程的最难部分之一。
成员逐一初始化
当在默认情形下,我们以某个类对象作为另外一个类对象的初值:
Triangular tri1(8);
Triangular tri2=tri1;
默认的成员逐一初始化操作:
类成员会被依次复制:Triangular类的_length,_beg_pos,_next都会依次从tri1复制到tri2。
复制构造函数可以改变默认的成员逐一初始化操作:
Matrix::Matrix(const Matrix &rhs)
:_row(rhs._row),_col(rhs._col)
{
int elem_cnt=_row*_col;
_pmat=new double[elem_cnt];
for(int ix=0;ix<elem_cnt;++ix)
{
_pmat[ix]=rhs._pmat[ix];
}
}
- 在设计class时,必须知道在此类之上进行成员逐一初始化的行为模式是否适当,如果适当,就不用提供复制构造函数,否则必须提供复制构造函数并在其中编写正确的初始化操作;
- 如果有必要为某个类编写复制构造函数,那就同样有必要为这个类编写复制赋值操作符,详见【C++】class的设计与使用(八)复制构造函数、复制赋值运算符。