初始化列表
1.初始化和赋值的概念:
首先我们先来了解一下成员变量初始化和赋值的概念,初始化是是对成员变量进行一次赋值,注意是只能一次赋值,而赋值是可以多次进行赋值的。
2.初始化列表的引出:
我们知道了初始化和赋值的概念之后,我们知道构造函数可以对成员变量进行初始化,但在构造函数体中的赋值真的是初始化吗?我们来验证一下吧!
Date(int year=0,int month=0,int day=1)
{
_year = year;
_month = month;
_day = day;
_year = 2;
_month = 2;
_day = 2;
}
上面的代码就是一个构造函数,对年月日进行初始化,我们可以看到在构造函数体中,我对年月日进行了两次的赋值操作,如果编译运行没问题,则根据赋值和初始化的概念就可以得出在函数体中的赋值不是初始化。那么我们来看看代码运行的结构吧。
我们可以看到,在构造函数体中我们可以进行多次的赋值操作,那么证明在构造函数体中的赋值并不是真正的初始化。
3.初始化列表
(1)初始化列表语法格式:以一个冒号开始,接着是以一个逗号分隔的数据成员列表,每一个**"成员变量"后面跟一个放在括号中的初始值**/表达式
看文字定义是不是有点蒙,没关系,下面举一个例子就一下子明白了。
Date(int year=0, int month=1, int day=1)
:_year(year)//year表示形参所接收到的值
, _month(month)//month表示形参所接收到的值
, _day(day)//day表示形参所接收到的值
{
}
看一下代码运行结果
这个就是初始化列表的定义!
(2)定义初始化列表需要注意的事项:
1.每一个成员变量只能在初始化列表中出现一次。
2.类中出现引用(在创建时就必须初始化了,而不是实例化时才进行初始化),const(只能进行一次的初始化)
3.自定义类型成员(且该类没有默认构造函数时)必须使用初始化列表进行初始化(没有默认的构造函数的自定义成员变量如果使用构造函数体进行初始化会调用它自身的拷贝构造函数,如果使用初始化列表会减少不必要的拷贝构造,提高效率)。
4.尽量使用初始化列表进行初始化
5.成员变量在类中的声明次序,就是成员变量初始化的顺序,与它在初始化列表中初始化的顺序无关。
这个是在类中的成员变量声明的顺序,下面我们来看看它们在初始化列表中的初始化顺序
int _year;//这里命名加_是为了和形参区别开来
int _month;
int _day;
explicit关键字
众所周知,构造函数不仅可以用于初始化成员变量。也可以对于只有单个参数或第一次参数无默认值,其余参数均有默认值的构造函数进行类型的转换,虽然这个类型转换大多数情况是意外的,
class Date
{
public:
Date(int year,int month=1,int day=1)
: _year(year)
{
}
private:
int _year;//这里命名加_是为了和形参区别开来
int _month;
int _day;
};
int main()
{
Date d1(2023);
d1 = 2022;
return 0;
}
这个代码运行没有任何问题,但是我们看一下Date成员实例化时,明明Date是一个日期值,有年月日,但现在只给一个整形值就可以初始化了这个日期类了,这是为什么呢?
实际上是编译器会把2023构造成一个无名的类,然后再把这个无名的类对d1进行赋值,这个就是隐式类型转换。
如果我在构造函数前面加上explicit关键字呢?
代码直接就报错了,这个证明explicit是为了防止构造函数进行隐式类型转换的关键字。
static成员
(1)定义:
在c语言中我们就学习过static关键字了,用static修饰一个变量,让这个变量变成静态成员变量,从而延长它的生命周期。
在c++中static不仅可以修饰一个成员变量,还可以修饰成员函数,
修饰的成员变量叫静态成员变量,修饰的成员函数叫静态成员函数,
静态成员变量一定是在类外进行定义(静态成员变量要在类对象被创建之前就要初始化了,如果在类中定义就无法达到在类对象创建之前进行初始化)
class Date
{
public:
private:
//静态成员变量的声明
static int _year;//这里命名加_是为了和形参区别开来
};
//静态成员变量的定义
int Date::_year = 1;
(2)static成员特性
1.静态成员为所有类的对象进行共享,存放在数据段中。
2.静态成员必须在类外进行定义,在类外进行定义时,不需要加static关键字,在类中只是声明
3.类静态成员可以使用类名::静态成员/对象.静态成员进行访问
4.静态成员没有this指针,不能访问非静态成员,非静态成员可以访问静态成员。
5.静态成员也受访问限定符的限制
(3)练习
实现一个类,计算程序中一共创建了多少个类对象
我们知道创建类对象时,一定会调用构造函数/拷贝构造函数进行初始化,调用析构函数进行销毁。所以当调用一次构造函数/拷贝构造函数时,那么我就++计数的静态成员变量,调用一次析构函数,那么我就–计数的静态成员变量
class A
{
public:
A()
{
_count++;
}
A(const A& count)
{
_count++;
}
~A()
{
_count--;
}
void Print()
{
cout << _count << endl;
}
private:
static int _count;
};
int A::_count = 0;
int main()
{
A d1;
A d2;
A d3;
A d4;
A d5;
return 0;
}
总结:
今天总结了初始化列表和explicit关键字和static关键字,内容有点多,可以慢慢消化,加油!