静态成员 static
静态成员:被static修饰的成员变量/函数,只占一份内存
- 存储在数据段(全局区,类似于全局变量)
-
可以通过
-
对象访问(对象.静态成员)
-
对象指针访问(对象指针->静态成员)
-
类访问(类名::静态成员)
Car::m_price = 400
-
-
必须初始化,必须放在类外面初始化再使用,在外面不能再写static了
不能使用int m_price = 0;
,这样只是初始化了一个同名的变量。 -
就算在main里没有创建Car对象,直接打印
Car::m_price
也可以,不依赖类存在,因为是全局变量 -
对比全局变量,它可以设定访问权限(public、protected、private),达到局部共享的目的
-
如果类的声明和实现分离,比如类的声明在.h文件,具体实现在.cpp文件,需要在.cpp中初始化。
静态成员函数
被static修饰的成员函数
只要是静态成员,都有三种访问方式(对象、指针、类)
-
内部不能使用this指针
也不能访问内部成员变量(相当于使用this)
this指针只能用在非静态成员函数内部
-
静态成员函数不能是虚函数
虚函数只能是非静态成员函数
-
静态成员内部不能访问非静态成员变量\函数,只能访问静态成员变量\函数
-
非静态成员函数内部可以访问静态函数变量\函数
-
构造函数、析构函数不能是静态
因为构造函数和析构函数是针对对象的,静态成员并不在对象内
-
当声明和实现分离时,实现部分不能带static
static应用
单例模式
设计模式的一种,保证某个类永远只创建一个对象
- 构造函数\析构函数私有化
- 定义一个私有的static成员变量指向唯一的那个单例对象
- 提供一个公共的访问单例对象的接口
class Rocket {
private:
Rocket() {}
~Rocket() {}
static Rocket *ms_rocket;
public:
static Rocket *sharedRocket() {
// 这里要考虑多线程安全
if (ms_rocket == NULL) {
ms_rocket = new Rocket();
}
return ms_rocket;
}
static void deleteRocket() {
if (ms_rocket != NULL) {
delete ms_rocket;
}
}
}
Rocket *Rocket::ms_rocket = NULL;
int main() {
Rocket *p = Rocket::sharedRocket();
}
无论调用多少次shareRocket,返回的地址都是一样的。
-
完善
int main() { Rocket *p1 = Rocket::sharedRocket(); Rocket *p2 = Rocket::sharedRocket(); return 0; } // p1和p2的地址是一样的
-
不允许有赋值操作,比如
p1 = p2
,这样是没有意义的,应该被禁止。所以就使用运算符重载来禁止。
直接将赋值运算符私有化,这样赋值就会被禁止。
-
其次拷贝构造函数也应该被私有化
class Rocket { private: Rocket() {} ~Rocket() {} static Rocket *ms_rocket; void operator=(const Rocket& rocket) {} public: static Rocket *sharedRocket() { // 这里要考虑多线程安全 if (ms_rocket == NULL) { ms_rocket = new Rocket(); } return ms_rocket; } static void deleteRocket() { if (ms_rocket != NULL) { delete ms_rocket; } } }
-
new\delete误区
int *p = new int; // 从堆空间分配四个字节给p
*p = 10;
delete p;
// 回收堆空间
并不是说把p的四个字节清空
回收堆空间内存:这块堆空间内存可以重新被别人使用。然后再new int,可能被分配到的字节是之前被用过的字节
如果销毁同时清零会浪费效率。
所以如果需要清零就手动清零