一、初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
注意:
1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2.
类中包含以下成员,必须放在初始化列表位置进行初始化:
①引用成员变量
②const成员变量
③自定义类型成员(
且该类没有默认构造函数时
)
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
4.成员变量在类中
声明次序
就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分割的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式
注意:
1、每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2、类中包含以下成员,必须放在初始化列表位置进行初始化:
引用成员变量
const 成员变量
自定义类型成员(且该类没有默认构造函数)
class Time
{
public:
//Time(int hour = 0) // 显示写默认构造
Time(int hour) // 不是默认构造 编译错误
{
_hour = hour;
}
private:
int _hour;
};
class Date
{
public:
// 要初始化 _t 对象,可以在函数体内赋值初始化,但是还是会走初始化列表,调用 Time 的默认构造
//Date(int year, int hour)
//{
// // 函数体内初始化
// _year = year;
// Time t(hour);
// _t = t;
//}
// 自定义类型成员没有默认构造函数的话,要初始化 _t 对象, 只能通过初始化列表
Date(int year, int hour, int& y)
:_t(hour) // 没有默认构造 就要用初始化列表
, _N(10)
, _ref(y)
{
_year = year;
_ref++; // 如果是 int y 那么 ++ 只改变 y ,不改变 x
}
private:
int _year;
Time _t;
const int _N;
int& _ref;
};
// 结论:自定义类型成员,推荐用初始化列表初始化
// 初始化列表可以认为是成员变量定义的地方
// 内置类型也推荐使用初始化列表,当然内置类型在函数体内初始化也没有什么明显的问题。
// 统一的建议的话:能使用初始化列表就使用,使用初始化列表基本没什么问题
int main()
{
int x = 2;
Date d(2022, 3, x);
return 0;
}
// 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print()
{
cout << _a1 << " " << _a2 << endl;
}
private:
// 声明
int _a2;
int _a1;
};
int main()
{
A aa(1);
aa.Print(); // 1 随机值
return 0;
}
二、explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。
用explicit修饰构造函数,将会禁止构造函数的隐式转换。
// explicit 关键字 + 匿名对象
class Date
{
public:
//explicit Date(int year)
// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
Date(int year)
:_year(year)
{
cout << "Date(int year)" << endl;
}
Date(const Date& d)
{
cout << "Date(const Date& d)" << endl;
}
~Date()
{
cout << "~Date()" << endl;
}
private:
int _year;
};
int main()
{
Date d1(2022); // 直接调用构造
Date d2 = 2023; // 隐式类型转换: 构造 + 拷贝构造 + 编译器优化 ==> 直接调用构造
// 匿名对象
Date(2021); // 生命周期就在这一行
return 0;
}
二、static成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
特性:
1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5. 静态成员也是类的成员,受
public
、
protected
、
private 访问限定符的限制
// static 成员
class A
{
public:
A()
{
++_scount;
}
A(const A& t)
{
++_scount;
}
// 静态成员函数 —— 没有 this 指针
static int GetCount()
{
//_a = 1; // 没有 this 指针 只能访问静态的不能访问非静态成员
return _scount;
}
private:
int _a;
// 静态成员变量属于整个类,生命周期整个程序运行期间,存在静态区
static int _scount; // 声明
};
// 类外面定义初始化
int A::_scount = 0;
int main()
{
A a1;
A a2;
A a3;
// 如果 _scount 不是私有条件下
// a1 a2 a3 三个对象访问的 _scount 都是共有的
// 而 _a 是每个对象下的 _a
//cout << a1._scount << a1._a << endl;
//cout << a2._scount << a2._a << endl;
//cout << a3._scount << a3._a << endl;
//cout << A::_scount << endl;
// 如果 _scount 是私有条件下 可以创建 static int GetCount 函数访问
cout << a1.GetCount << endl;
cout << A::GetCount << endl;
return 0;
}