目录
一、初始化列表
初始化列表:是以冒号开始,后面接一个以逗号隔开的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式。
class Date
{
public:
Date(int year, int month, int day): _year(year), _month(month), _day(day)
{}
private:
int _year;
int _month;
int _day;
};
【注意】
1)每个成员变量在初始化列表中只能出现一次(只能进行一次初始化)
2)类包含以下成员,必须放在初始化列表位置进行初始化:
- 引用成员变量(引用必须在定义的时候初始化,并且不能重新赋值)
- const成员变量(常量只能初始化不能赋值)
- 类类型成员(该类没有默认构造函数,使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化)
class A
{
public:
A(int a):_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref):_aobj(a),_ref(ref),_n(10)
{}
private:
A _aobj; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};
3)尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
class Time
{
public:
Time(int hour = 0):_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
Date(int day)
{}
private:
int _day;
Time _t;
};
int main()
{
Date d(1);
}
4)成员变量是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的
class foo
{
public:
foo(int x):i(x), j(i){}; // ok, 先初始化i,后初始化j
private:
int i ;
int j ;
};
再对比下面的代码:
class foo
{
public:
foo(int x):j(x), i(j){} // i值未定义
private:
int i ;
int j ;
};
这里i的值是未定义的因为虽然j在初始化列表里面出现在i前面,但是i先于j定义,所以先初始化i,而i由j初始化,此时j尚未初始化,所以导致i的值未定义。一个好的习惯是,按照成员定义的顺序进行初始化。
二、explicit关键字
C++中的explicit关键字用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式).
在C++中, 如果的构造函数只有一个参数时, 那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象.
class Date
{
public:
Date(int year):_year(year)
{}
explicit Date(int year):_year(year)
{}
private:
int _year;
int _month:
int _day;
};
void TestDate()
{
Date d1(2018);
// 用一个整形变量给日期类型对象赋值
// 实际编译器背后会用2019构造一个无名对象,最后用无名对象给d1对象进行赋值
d1 = 2019;
}
上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换
三、static成员
1、定义
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化。
class A
{
public:
A() {++_scount;}
A(const A& t) {++_scount;}
// 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数
static int GetACount() { return _scount;}
private:
static int _scount;
};
// 静态成员必须在定义类的文件外对静态成员变量进行初始化,否则会编译出错。
int A::_scount = 0;
void TestA()
{
cout<<A::GetACount()<<endl;
A a1, a2;
A a3(a1);
cout<<A::GetACount()<<endl;
}
2、特性
1)静态成员为所有类对象所共享,不属于某个具体的实例
2)静态数据成员在定义或说明时前面加关键字static,初始化在类体外进行,而前面不加static,(这点需要注意)以免与一般静态变量或对象相混淆。
静态数据成员初始化的格式如下:
<数据类型> <类名>::<静态数据成员名>=<值>
(初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。)
3)类静态成员访问有两种方法:①类名::静态成员;②对象.静态成员
4)静态成员函数没有隐藏的this指针,不能访问任何非静态成员,也不能调用非静态成员函数。
5)静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值
6)非静态成员函数可以访问静态数据成员。