要明白这个用法,我们首先要了解c/c++的内存分布,以及static所在的区间。
对于一个完整的程序,在内存中分布情况如下:
1.栈区:由编译器自动分配释放,像局部变量,函数参数,都是在栈区。会随着作用于退出而释放空间。
2.堆区:程序员分配并释放的区域,像malloc(c),new(c++)
3.全局数据区(静态区):全局变量与静态变量的存储是放在一起的,初始化的全局变量与静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束释放。
4.代码区。
代码如下:
#include
void test()
{
static int a = 1;
a++;
printf("%d ", a);
}
int main(void)
{
int i = 0;
while (i <= 10)
{
test();
i++;
}
return 0;
}
输出:
2 3 4 5 6 7 8 9 10
static修饰局部变量时,会影响局部变量的生命周期,本质上改变了局部变量的存储位置,生命周期变长,为整个周期。静态局部变量存储于进程中的全局数据区。
首先我们要知道全局变量的属性:全局变量具有外部链接属性。而static修饰全局变量时,这个全局变量的外部链接属性变为内部链接属性,是其他源文件(.c)文件就可以再使用这个全局变量了。则使用时我们会感觉到该全局变量作用域变小。
static int i = 1; //note:3
//int i = 1; //note:4
int foo()
{
i += 1;
return i;
}
静态全局变量不能被其它文件所用(全局变量可以);
其它文件中可以定义相同名字的变量,不会发生冲突(自然了,因为static隔离了文件,其它文件使用相同的名字的变量,也跟它没关系了);
准确的说,静态函数跟静态全局变量的作用类似:
//file a.c
#include
static void fn()
{
printf("this is non-static func in a");
}
//file b.c
#include
extern void fn(); //错误,不能使用extern声明其他文件的fn(),供本文件使用。
void main()
{
fn();
}
总的来说:
c语言中的static中的两种用法:
一种是文件隔离:就是static修饰的变量或者函数不能在别的文件用extern修饰然后调用,可以靠引用.h文件来引用。
另外一种就是:用它修饰的函数局部变量只能在函数内被改变,但是生命期贯穿整个程序。
用于修饰class的静态成员,这种数据成员的生存期大于class的对象(实体instance)。静态数据成员是每个class都有一份,普通数据成员是每个class有一份,普通数据成员是每个instance有一份,因此静态数据成员也叫作类变量,而普通数据成员也叫作实例变量。
多个成员共享同一个static成员
#include
#include
using namespace std;
class Test
{
public:
Test(int a, int b, int c) :
m_a(a),
m_b(b),
m_c(c)
{
m = a + b + c;
}
void Show()
{
cout << "m = " << m << endl;
}
private:
int m_a, m_b, m_c;
static int m;
};
int Test::m = 0; //初始化静态数据成员
int main()
{
Test ClassA(1, 1, 1);
ClassA.Show(); //输出: 3
Test ClassB(3, 3, 3);
ClassB.Show(); //输出: 9
ClassA.Show(); //输出: 9,B中的m改变了,A中的m也会改变
system("pause");
return 0;
}
静态成员变量特点:
1:所有类的实例中,共享类中的静态成员变量;2:类的静态成员变量在没有类的实例的情况下,依然可以访问;
3:类的静态成员变量并不完全属于类。
没有实例化时,可以通过如下进行访问 :
Test::m
属于类的地方:
可以通过实例化或者非实例化进行访问,
不属于类的地方:
static成员函数不占用类的内存空间,因为static修饰后存放在了全局区,而类中的非静态变量是在创建类的实例的时候分配内存,可能存储在栈,堆。
在声明时就初始化静态成员,可以使用这样的成员来计算我们申请了多少个实例
class T
{
inline static int count {0};
public:
int hp;
T()
{
count++;
}
int GetCount()
{
return count;
}
~T()
{
count--;
}
};
int main()
{
}
具体要搞清楚很复杂,先不管 ,可以参考一下这个博客,但也不是很全
【C++】类中静态(static)成员变量、静态(static)成员函数和静态常量(static const)的应用_静态成员变量-CSDN博客
我们可以利用static关键字声明一个类的静态成员函数,类的静态成员函数有如下特点: 我们可以利用静态关键字声明一个类的静态成员函数,类的静态成员函数有如下特点:
(1) 不管有没有创建类的实例,都可以访问类的静态成员函数
(2) 类的静态成员函数不能访问非静态的成员变量
(3) 类的静态成员函数不能是const
(4) 类的静态成员函数不能使用this指针
观察如下代码:
class T
{
const static int count {};
public:
int hp;
static void Test()
{
hp++//错误,因为static成员函数不实例化也可以访问,那么这里面就不能访问非static成员变量
this->hp++;//错误,this指向当前的对象,但如果没有实例化,那么就冲突了
}
static void Test()const //错误,这样写没有意义
{
}
T()
{
}
int GetCount()
{
return count;
}
~T()
{
}
};
int main()
{
}
未实例化时,也是通过如下进行访问:
T::test()
在 C++ 语言中 , " 友元类 " 是 一个类 与 另外一个类 的 特殊类关系类 ,在 类 A 的 " 友元类 " B 中 , 可以直接访问 A 类 的 私有成员 和 受保护成员 ;
B 是 A 的好朋友 , B 可以访问 A 的所有成员 ;
全局函数做友元访问类的私有成员的示例代码 :
class T
{
int hp;
int mp;
void GetHP()
{
std::cout << hp;
}
friend void SetHP(T& t1);
friend void SetMP(T& t1);
};
void SetMP(T& t1)
{
t1.mp = 2500;
t1.GetHP();
}
void SetHP(T& t1)
{
t1.hp = 2500;
t1.GetHP();
}
int main()
{
T t1;
SetHP(t1);
}
输出:
2500
声明一个 类 B 是 另一个类 A 的 友元类 , 可以 在类 A 中使用 friend 关键字来声明 ;
B 是 A 的 友元类 ;
B 类中定义 A 类型成员变量 ;
B 可以访问 A 中的 所有成员 , 包括 私有成员 或 受保护成员 ;
B 可以看做 A 的 数据操作辅助类 ;
class Student
{
private:
// 声明 StudentCaculate 类是 Student 类的友元类
// 在 StudentCaculate 类中可以访问 Student 类中的私有成员
friend class StudentCaculate;
}
实例代码:
class T1;
class T
{
int hp;
int mp;
void GetHP()
{
T1 x;//T1为T的友元,所以可以在T中调用T1的成员
x.GetHP();
std::cout << hp;
}
friend class T1;
friend void SetHP(T& t1, T1& t2);
friend void SetMP(T& t1, T1& t2);
};
class T1
{
int hp;
int mp;
void GetHP()
{
T t1;
t1.GetHP();
std::cout << hp;
}
friend class T;
friend void SetHP(T& t1,T1& t2);
friend void SetMP(T& t1,T1& t2);
};
友元类性质:
1.友元类单向性
友元类单向性 :
友元类关系是单向的 , 声明一个类 B 是 另一个类 A 的 友元类 ,
B 可以访问 A 的 所有成员 ,
但是 A 不是 B 的友元类 , A 不能访问 B 的私有和保护成员 ;
2.友元类继承性
友元类 关系不具有继承性 , 即 子类不能直接继承父类的友元类 ;
3.友元类作用
友元类主要作用 :
作为 某个类的 数据操作 辅助类 ;
作为 多个类 之间 传递信息 的 辅助类 ;
#include
#include
using namespace std;
class Building;
class LaoWang
{
public:
LaoWang();
void visit1(); //让visit1()函数 可以 访问Building中的私有成员
void visit2(); //让visit2()函数 不可以 访问Building中的私有成员
Building *building;
private:
};
class Building
{
// 告诉编译器,LaoWang类下的visit1()函数是Building类的好朋友,可以访问Building的私有成员
friend void LaoWang::visit1();
public:
Building();
string m_SittingRoom; //客厅
private:
string m_BedRoom; //卧室
};
LaoWang::LaoWang()
{
building = new Building;
}
void LaoWang::visit1()
{
cout << "隔壁老王LaoWang类中的visit1()函数正在访问:" << building->m_SittingRoom << endl;
cout << "隔壁老王LaoWang类中的visit1()函数正在访问:" << building->m_BedRoom << endl;
}
void LaoWang::visit2()
{
cout << "隔壁老王LaoWang类中的visit2()函数正在访问:" << building->m_SittingRoom << endl;
//cout << "隔壁老王LaoWang类中的visit2()函数正在访问:" << building->m_BedRoom << endl; //错误!私有属性不可访问
}
Building::Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
void test()
{
LaoWang lw;
lw.visit1();
lw.visit2();
}
int main()
{
test();
return 0;
}