c++中static的用法

今天看看static这个关键字用法

static的作用总的来说有两种:

限定作用域
保持变量内容持久化

对于c下面的static用法与cpp下面的基本差不多

cpp中static用法

1 类的静态成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct A{

int getdata() //非静态成员函数可以调用静态成员变量,反之则不行
{
return val;
}
void setData(int av)
{
val = av;
}
private:
static int val; //类的静态成员变量
static int func(int x) //类的静态成员函数
{
printf("==%d==\n",x);
return 0;
}
};

一般声明都是在.h文件中,实现在cpp文件。
对于静态成员变量在cpp中文件必须对其初始化,初始化时候使用类名加作用域运算符。
如果不初始化就使用的话,会报错。例如上面的非静态成员方法getdata(),如果静态成员变量val没有初始化,会报错A::val是未定义的引用
正确的初始化如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct A{
int getdata() //非静态成员函数可以调用静态成员变量,反之则不行
{
return val;
}
void setData(int av)
{
val = av;
}
private:
static int val; //类的静态成员变量
static int func(int x) //类的静态成员函数
{
printf("==%d==\n",x);
return 0;
}
};
int A::val =2; //cpp文件中对其进行初始化,别人才可使用它
int main(int argc, char const *argv[])
{
A a,b;
std::cout<<a.getdata()<<std::endl;
a.setData(174);
std::cout<<b.getdata()<<std::endl;
return 0;
}

像上面这样使用类的静态成员变量是没有问题的,该成员变量属于类的所有成员实例共有,只有一个拷贝

2 类的静态成员函数

如上面的func函数,单独在cpp中实现的时候,前面是不需要带static关键字的。
类的静态成员函数是类全局的,静态的成员只能访问静态的成员,这里static关键字并没有改变private的访问作用域
将上面的代码规范化写下,分为h文件和cpp文件

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <stdio.h>

struct A{
int getdata();
void setData(int av);

private:
static int val;
static int func(int x);
};

可以看到其实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <stdio.h>
#include "StaticTest.h"

int A::getdata() //非静态成员函数可以调用静态成员变量,反之则不行
{
return val;
}
void A::setData(int av)
{
val = av;
}
int A::val =2; //cpp文件中对其进行初始化,别人才可使用它
int A::func(int x) //类的静态成员函数,不需要前面的static关键字
{
printf("==%d==\n",x);
return 0;
}

int main(int argc, char const *argv[])
{
A a,b;
std::cout<<a.getdata()<<std::endl;
a.setData(174);
std::cout<<b.getdata()<<std::endl;
//尝试直接只用private的静态成员函数
//A::func(20); 报错, error: static int func(int x) is private
return 0;
}

那么这里就疑问,private的static成员函数到底有啥用,外面也不能调用private的方法
那么只能在h头文件里面加上public的函数来回调这个private的static方法

1
void callPrivateFunc(int value);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void A::callPrivateFunc(int value)
{
func(value);//public的普通方法调用private的static方法
}
int main(int argc, char const *argv[])
{
A a,b;
std::cout<<a.getdata()<<std::endl;
a.setData(174);
std::cout<<b.getdata()<<std::endl;
//A::func(147);
a.callPrivateFunc(147);
return 0;
}

这样是可正常调用的。总结了下private的静态成员变量或者方法的话,目前只用私有静态成员变量貌似可以用来实现一个单例模式。这个后面小节补充一下网上看到的例子。
注意:静态成员可以被继承或覆盖,但不能是虚函数,

因为static是与类相关的,而不是运行时候绑定
静态成员函数没有this指针,this指针是指向对象的,而静态函数是属于类的
静态成员函数不能是const类型的,首先一般函数中this指针是一个指向对象的常量指针,普通的const函数限定了常量指针this所指向的对象也是
一 个常量,即通过this指针无法修改对象的。也就是const函数是必须要this指针 ,而static函数是没有this指针的。

3 只在cpp文件内有效的static变量

在cpp文件的全局范围内声明

1
static int a =0

与声明普通的全局变量

1
int b =1;

是不同的。
static关键字限定了这个全局的作用范围是本cpp文件,其他的cpp文件是不能访问这个变量的;
若两个cpp文件中都有这样的全局变量,则他们是两个不同的变量。
这里关于cpp文件内的访问代码解释下:
我们在StaticVar1.cpp文件中定义静态的全局变量globalv1

1
static int globalv1 = 12345;

在StaticVar2.cpp定义普通的全局变量globalv2

1
int gloablv2 =54321;

然后一个测试文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <stdio.h>

//这里对于全局变量的访问,我们是用的extern
extern int globalv1; //声明的时候不需要static,不然编译器会认为是命名冲突
extern int gloablv2;

int main(int argc, char const *argv[])
{
/* code */
std::cout<<globalv1<<std::endl; //error : globalv1 was not declared in this scope
std::cout<<globalv2<<std::endl;
return 0;
}

会发现static的全局变量范围不能在其他cpp文件中使用。

3.1 static的多层含义

static的第一种含义:修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
static的第二种含义:修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
static的第三种含义:修饰函数时,表明该函数只在同一文件中调用。
static的第四种含义:修饰类的数据成员,表明对该类所有对象这个数据成员都只有一个实例。即该实例归 所有对象共有。
static在c++中的第五种含义:用static修饰不访问非静态数据成员的类成员函数。这意味着一个静态成员函数只能访问它的参数、类的静态数据成员和全局变 量

4 只在cpp文件内有效的static函数

static全局函数的情况与static全局变量的情况一样的,这里不赘述。

5 利用静态变量、静态成员函数,私有静态变量实现一个单例

一个Singleton类,然后实现

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

using namespace std;

struct Singleton
{
static Singleton* getInstance();//静态函数
protected:
Singleton();
private:
static Singleton* instance;//私有静态变量
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Singleton.h"
#include <iostream>

using namespace std;

Singleton* Singleton::instance = NULL;//私有静态成员变量的初始化,不需要再写static
Singleton::Singleton()
{
cout<<"Singleton...构造函数"<<endl;
}

Singleton* Singleton::getInstance()//实现的时候不需要static
{
if(instance == NULL)
{
instance = new Singleton();
}
return instance;
}
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "Singleton.h"

using namespace std;

int main(int argc, char const *argv[])
{
Singleton* sgn = Singleton::getInstance();
return 0;
}