类与对象的本质

1.static

1.1 c语言用法-static修饰局部变量

要明白这个用法,我们首先要了解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修饰局部变量时,会影响局部变量的生命周期,本质上改变了局部变量的存储位置,生命周期变长,为整个周期。静态局部变量存储于进程中的全局数据区。 

1.2 c语言用法-static修饰全局变量

 首先我们要知道全局变量的属性:全局变量具有外部链接属性。而static修饰全局变量时,这个全局变量的外部链接属性变为内部链接属性,是其他源文件(.c)文件就可以再使用这个全局变量了。则使用时我们会感觉到该全局变量作用域变小。

static int i = 1;  //note:3
//int i = 1;  //note:4
 
 
int foo()
{
	i += 1;
	return i;
}

静态全局变量不能被其它文件所用(全局变量可以);
其它文件中可以定义相同名字的变量,不会发生冲突(自然了,因为static隔离了文件,其它文件使用相同的名字的变量,也跟它没关系了); 

1.3 c语言用法-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文件来引用

另外一种就是:用它修饰的函数局部变量只能在函数内被改变,但是生命期贯穿整个程序。

 1.4 C++-静态成员变量

1.4.1 概念阐述

用于修饰class的静态成员,这种数据成员的生存期大于class的对象(实体instance)。静态数据成员是每个class都有一份,普通数据成员是每个class有一份,普通数据成员是每个instance有一份,因此静态数据成员也叫作类变量,而普通数据成员也叫作实例变量

类与对象的本质_第1张图片

 多个成员共享同一个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修饰后存放在了全局区,而类中的非静态变量是在创建类的实例的时候分配内存,可能存储在栈,堆。

1.4.2 在类的声明中通过inline定义静态成员(c++17新特性)

 在声明时就初始化静态成员,可以使用这样的成员来计算我们申请了多少个实例

class T
{
	inline static int count {0};
public:

	int hp;
	T()
	{
		count++;
	}
	int GetCount()
	{
		return count;
	}

	~T()
	{
		count--;
	}
};

int main()
{
	
}

1.4.3 静态成员常量 

类与对象的本质_第2张图片

具体要搞清楚很复杂,先不管 ,可以参考一下这个博客,但也不是很全

【C++】类中静态(static)成员变量、静态(static)成员函数和静态常量(static const)的应用_静态成员变量-CSDN博客

1.5 c++-静态成员函数

我们可以利用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()

 2. 友元类

2.1 引入

在 C++ 语言中 , " 友元类 " 是 一个类 与 另外一个类 的 特殊类关系类 ,在 类 A 的 " 友元类 " B 中 , 可以直接访问 A 类 的 私有成员 和 受保护成员 ;

B 是 A 的好朋友 , B 可以访问 A 的所有成员 ;

 2.2 友元作用于全局函数

全局函数做友元访问类的私有成员的示例代码 :

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 

2.3 友元作用于类

声明一个 类 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.友元类作用

友元类主要作用 :

作为 某个类的 数据操作 辅助类 ;
作为 多个类 之间 传递信息 的 辅助类 ;

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;
}

类与对象的本质_第3张图片

 3.嵌套类

你可能感兴趣的:(java,jvm,开发语言)