文章目录
- 一、初始化列表
- 二、静态(static)成员
一、初始化列表
类对于成员变量的赋值有两种方式
- 函数体内赋值
- 初始化列表
函数体内赋值就是直接在构造函数中赋值即可,而初始化列表它是较为特殊的一种方式!
初始化列表是在构造函数()之后以:
开始,然后后面跟要初始化的变量,之后再跟(),括号里面的值或者表达式就是对这个变量的初始化!然后再以,
作为分割,之后可以再跟成员变量赋值或者不跟,没有就不用再用逗号分割!
如下:
为什么要出来初始化列表?函数体内赋值不好吗?
因为有些情况只有初始化列表才能完成!
如:引用、const修饰的、自定义类型(没有默认构造函数)
引用和const都是必须在定义的时候初始化赋值!
而const 修饰的不在定义的时候初始化,那么就改不了它了,他就是一个随机值了!
而类对象成员变量它的定义不是在类中,类里面仅仅只是对其声明,真正定义是在对象定义之后,对象调用它的构造函数在其初始化列表对其定义,而这些并不是在构造函数函数体内定义,函数厅内赋值仅仅只是对其再次赋值而已!如:成员变量中有自定义类型时,都说它会去自动调用这个自定义类型的构造函数,但是这是建立在它的构造函数是默认构造的前提下,如果不是就不行了!自定义类型成员它的调用是在初始化列表完成的!
成员是引用、const修饰,自定义类型
class stack
{
public:
stack(int capacity)
{
_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
{
perror("malloc fail\n");
exit(-1);
}
_top = 0;
_capacity = capacity;
}
private:
int* _a;
int _top;
int _capacity;
};
class B
{
public:
B(int& a,int b = 2)
:_a(a)
,_b(b)
,_st(10)
{
}
private:
int& _a;
const int _b;
stack _st;
};
并且不能将其写在函数体内,只能写在初始化列表!
类成员变量的定义是在初始化列表定义的,他只是在类里面声明而已,所有这三类只能写在初始化列表!
而当不在初始化列表显示写出时,其实它也是定义好了的!我没在函数体内给它赋值,那么就是每给它赋值,它的值就是随机值!
当初始化列表没有写出时,其实它们还是照样要走初始化列表完成定义!
既然初始化这么神奇,那么为什么不一开始直接用初始化列表?
因为初始化列表不能完成全部的工作,有些时候赋值完成之后还要检查,或者给空间赋值
初始化的!
如:
class BB
{
public:
BB(int capacity=4)
:_a((int*)malloc(sizeof(int)* capacity))
,_top(0)
,_capacity(capacity)
{
if (_a == nullptr)
{
perror("malloc fail\n");
exit(-1);
}
memset(_a, 0, sizeof(int) * _capacity);
}
private:
int* _a;
int _top;
int _capacity;
};
这段代码它仅仅只是在初始化列表完成初始化还是不够的,还需要检查_a开的空间是否成功,这时在初始化列表中就无法完成,需要在函数体内完成!
还有就是动态开辟一个二维数组,只是初始化列表并不能完成,需要在函数体内完成!
class AA
{
public:
AA(int row=10,int col = 5)
{
_a = (int**)malloc(sizeof(int*) * row);
if (_a == nullptr)
{
perror("malloc fail\n");
exit(-1);
}
for (int i = 0; i < row; i++)
{
_a[i] = (int*)malloc(sizeof(int) * col);
if (_a[i] == nullptr)
{
perror("malloc fail\n");
exit(-1);
}
}
}
private:
int** _a;
};
动态开辟一个二维数组,是先将行开辟出来,然后再每一行有多少列开辟出来这样在初始化列表是无法完成的!需要在函数体内完成!就这样说吧,初始化列表能完成95%的事情但是剩下的5%需要在函数体内完成!
初始化列表初始化顺序与声明应一致
初始化列表在初始化声明的成员变量时,是按照声明的顺序进行初始化的!所有在初始化列表中,建议初始化顺序与声明顺序一致!
class C
{
public:
C(int a)
:_a(a)
,_b(_a)
{}
void Print()
{
cout << _a << " " << _b << endl;
}
private:
int _b;
int _a;
};
int main()
{
C c(1);
c.Print();
return 0;
}
这段程序是没有保持一致的,它运行出来的结果如下:
二、静态(static)成员
先来看一个场景,场景需求是统计一个类创建了多少对象,其实创建了多少对象,在创建对象之后救护调用一次构造,所以可以定义一个全局变量cnt来统计,然后在构造函数中++,拷贝构造之中也要++,因为有时是以一个已经存在对象初始化另一个不存在的对象!
全局变量统计类创建了多少个对象
int cnt = 0;
class Count
{
public:
Count()
{
cnt++;
}
~Count()
{
cnt--;
}
};
Count c1;
void fun()
{
Count c2;
cout << __LINE__ << " " << cnt << endl;
}
int main()
{
cout << __LINE__ << " "<<cnt << endl;
Count c;
cout << __LINE__ << " " << cnt << endl;
fun();
cout << __LINE__ << " " << cnt << endl;
return 0;
}
其中的__LINE__是显示文件行
但是定义了这个全局变量,在任意位置都能修改它!这样不安全,为了不能修改它,将其封装到类中使其成为类成员变量!
但是它要与普通成员变量不同,将其弄成静态成员变量!在前面加static
那么普通成员变量与静态成员变量有什么区别?
普通成员变量:属于每一个类对象,存储在类对象中
静态成员变量:属于类,属于每一个类共享,存储在静态区!它不在初始化列表定义,因为它存储在静态区,将其定义在类外边!
但是这样它是私有成员变量,访问不了它,要访问它,可以将其弄成公有成员变量或者写一个公有函数获取它!这个成员函数也可以设置为静态成员函数!静态成员函数无this指针,它不能访问非静态成员变量或非静态成员函数!
静态成员统计类创建了多少个对象
class Count
{
public:
Count()
{
cnt++;
}
~Count()
{
cnt--;
}
static int Getcnt()
{
return cnt;
}
private:
static int cnt;
};
int Count::cnt = 0;
Count c1;
void fun()
{
Count c2;
cout << __LINE__ <<" "<< Count::Getcnt() << endl;
}
int main()
{
cout << __LINE__ << " " << Count::Getcnt() << endl;
Count c;
cout << __LINE__ << " " << Count::Getcnt() << endl;
fun();
cout << __LINE__ << " " << Count::Getcnt() << endl;
return 0;
}
只是将其弄成了静态成员函数之后,在这个函数体内无法调用类中的非静态成员函数,并且不能访问类中非静态成员变量!因为没有this指针!但是非静态成员函数可以调用静态成员函数和访问静态成员变量!
凡是经由static 修饰定义的都是存储在静态区去了,它的定义也就在类之外定义了!