中国大学MOOC程序设计与算法(三):C++ 面向对象程序设计 第三周 类和对象提高 笔记 之 静态成员变量、静态成员函数

本文深入探讨C++中静态成员变量和静态成员函数的概念及应用,解析其与普通成员的区别,包括内存分配时间、this指针传递以及成员函数间的访问特性。通过实例,展示静态成员在计数和统计场景中的优势。

第三周 类和对象提高
1.this指针
2.静态成员变量、静态成员函数
3.成员对象和封闭类
4.常量对象、常量成员函数、和常引用
5.友元

2.静态成员变量、静态成员函数

静态成员:在定义前面加了static关键字的成员。

class CRectangle
{
	private:
		int w, h;
		static int nTotalArea; // 静态成员变量
		static int nTotalNumber;
	public:
		CRectangle(int w_,int h_);
		~CRectangle();
		static void PrintTotal(); // 静态成员函数
};

静态成员变量

普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
如果改了一个对象的静态成员变量,那么同一类下其他所有对象的这个静态成员变量都一块改变了。描述的是这个类下所有对象的共有属性。必须在定义类的文件中对静态成员变量进行一次说明或初始化。否则编译能通过,链接不能通过。

sizeof 运算符不会计算静态成员变量,sizeof()是计算一个对象或一个变量的空间大小,静态成员变量不属于任意一个对象,是属于类的,所有对象共享。

class CMyclass {
	int n;
	static int s;
};
//sizeof( CMyclass ) 等于 4

静态成员函数:普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
因此静态成员不需要通过对象就能访问

如何访问静态成员

  1. 类名::成员名
    CRectangle::PrintTotal();
  2. 对象名.成员名
    CRectangle r;
    r.PrintTotal();//但是PrintTotal函数并不是作用在r这个对象上
  3. 指针->成员名
    CRectangle * p = &r;
    p->PrintTotal();//但是PrintTotal函数并不是作用在p这个对象上
  4. 引用.成员名
    CRectangle & ref = r;
    int n = ref.nTotalNumber;//nTotalNumber不是属于ref这个对象的,是属于CRectangle这个类的

静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。
静态成员函数本质上是全局函数。
设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一个整体,易于维护和理解。

例子:考虑一个需要随时知道矩形总数和总面积的图形处理程序,可以用全局变量来记录总数和总面积,用静态成员将这两个变量封装进类中,就更容易理解和维护。

class CRectangle
{
	private:
		int w, h;
		static int nTotalArea;
		static int nTotalNumber;
	public:
		CRectangle(int w_,int h_);
		~CRectangle();
		static void PrintTotal();
};
CRectangle::CRectangle(int w_,int h_){
	w = w_;
	h = h_;
	nTotalNumber ++;
	nTotalArea += w * h;
}
CRectangle::~CRectangle(){
	nTotalNumber --;
	nTotalArea -= w * h;
}
void CRectangle::PrintTotal(){
	cout << nTotalNumber << "," << nTotalArea << endl;
}
int CRectangle::nTotalNumber = 0;
int CRectangle::nTotalArea = 0;
//  必须在定义类的文件中对静态成员变量进行一次说明或初始化。否则编译能通过,链接不能通过。
int main()
{
	CRectangle r1(3,3), r2(2,2);
	//cout << CRectangle::nTotalNumber; // Wrong ,  私有
	CRectangle::PrintTotal();
	r1.PrintTotal();//和上一行是等价的
	return 0;
}
输出结果:
2,13
2,13

注意:
在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。原因是:静态成员属于类本身,不属于具体类对象,在类加载时分配内存空间,静态成员存在于普通成员之前,我们不能去访问一个内存中不存在的东西。

void CRectangle::PrintTotal()
{
	cout << w << "," << nTotalNumber << "," <<nTotalArea << endl; //wrong,w 到底是属于那个对象的?
}

上面的CRectangle类写法,有何缺陷?

在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象,比如调用一个以CRectangle类对象作为参数的函数时,或调用一个以CRectangle类对象作为返回值的函数时。临时对象在消亡时会调用析构函数,减少nTotalNumber 和nTotalArea的值,可是这些临时对象在生成时却没有增加nTotalNumber 和 nTotalArea的值。
解决办法:为CRectangle类写一个复制构造函数。

CRectangle :: CRectangle(CRectangle & r )
{
	w = r.w; 
	h = r.h;
	nTotalNumber ++;
	nTotalArea += w * h;
}

补充:普通成员又名非静态成员。静态(static)成员。类成员包括数据成员和成员函数。
两者区别:
1)分配内存的时间不同
静态成员属于类本身,不属于具体类对象,在类加载时分配内存空间,程序结束时才消失。可以类名直接访问。
普通成员属于类对象,在类对象创建时(类的实例)才会分配内存,即动态加载内存,不用时消失。通过类对象去访问。
静态成员属于类本身,不属于具体类对象,在类加载时分配内存空间,静态成员存在于普通成员之前,我们不能去访问一个内存中不存在的东西。
2)是否传递this指针
普通成员函数传递this指针。实质是一个包含指向具体对象的this指针的函数,即其隐式包含一个指向当前对象的this指针。
静态成员函数不传递this指针。
注:也就是说静态成员函数不接受隐含的this指针,无法直接访问类中的非静态成员。
3)成员函数间访问
普通成员可以访问静态成员;
静态成员函数只能通过对象间接引用非静态成员。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值