目录
一、初始化列表
1、什么是初始化列表?
初始化列表是一个类成员初始化的地方,也是构造函数的一部分,它位于构造函数的形参表和函数体之间;它以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class Date
{
public:
Date()
:_pi((int*)malloc(sizeof(int) * 5))
,_a(1)
,_ch('a')
{
//...
}
private:
int _a;
int* _pi;
char _ch;
};
2、为什么要初始化列表?
在类域私有的地方,那些类的私有成员变量都只是声明,并没有被初始化。所以当类被实例化之后,类里面的成员变量都是随机值。因此,类里面的私有成员必须要有一个地方给它们初始化——那就是初始化列表。
而且,像引用、const、自定义类型(没有默认构造函数)这种一被定义就要被初始化的类型就一定要在初始化列表初始化。
3、注意事项
在初始化列表中初始化成员变量也是存在先后顺序的。但其顺序并不一定是从上至下,而是根据成员变量在私有类域的声明顺序。因此,我们在初始化成员变量时应该与成员的声明顺序保持一致,否则可能会引起某个变量是随机值。
class Date
{
public:
Date()
:_pi((int*)malloc(sizeof(int) * 5)) //然后初始化
,_a(1) //首先初始化
,_ch('a') //最后初始化
{
//...
}
private:
int _a;
int* _pi;
char _ch;
};
4、explicit 关键字
当初始化变量时右值与左值的类型不同是,编译器会先生成一个临时变量并把右值的数据按字节拷到这个临时变量里,然后再把这个临时变量的数据赋值给左值。这就是隐式类型转换。
而 explicit 的意义就在于用explicit修饰构造函数,将会禁止单参构造函数的隐式类型转换。
class Date
{
public:
explicit Date(int year)
:_a(year)
,_pi((int*)malloc(sizeof(int) * 5))
,_ch('a')
{
}
private:
int _a;
int* _pi;
char _ch;
};
int main()
{
Date d1 = 2023;
return 0;
}
二、static成员
1、static 成员变量
(1)为什么要在类外初始化?
用 static 修饰的成员变量为静态成员变量。它并不在栈上,而是存在了静态区。但我们知道,当类实例化成对象时是在栈上实例化的,然而 static 修饰的变量却不在栈,因此 static 修饰的变量并不能被构造函数初始化,因此只能在类外初始化了。
但初始化的时候就要注意了,因为 static 修饰的成员变量已经在类里声明了,因此在初始化时就不用再在最前面加 static 修饰了,取而代之的是要在变量名前面加类型名和类名限定。
(2)为什么静态成员为所有类对象所共享,不属于某个对象?
在(1)中说了由于静态成员的存储位置是静态区,而不是栈,那么它自然就不属于某个对象了,但由于它在类中声明了,因此它是属于类的而不是属于对象的。同时也正是由于静态成员是属于类的,所以它遵守权限访问。
class Date
{
public:
Date(int year)
:_pi((int*)malloc(sizeof(int) * 5))
,_ch('a')
{
this->_a++;
}
private:
static int _a;
int* _pi;
char _ch;
};
int Date::_a = 10;
int main()
{
Date d1 = 2023;
return 0;
}
2、static 成员函数
(1)为什么静态成员函数不能访问非静态成员变量?
在 C++ 中,静态成员函数有一个十分重要的性质,就是没有隐含的 this 指针,因此无法访问非静态成员变量。
(2)静态成员函数可以调用非静态成员函数吗?
答:不可以。由于静态成员函数没有 this 指针,因此是不能通过 this 指针来访问成员函数,但如果在静态成员函数里创建了一个新的对象,那么是可以通过这个对象访问成员函数的。
(3)非静态成员函数可以调用类的静态成员函数吗?
答:可以。因为静态成员函数是属于类的,因此非静态成员函数是可以调用静态成员函数的,只不过调用时要制定类域。