c语言类静态数据成员函数,鸡啄米:C++编程入门系列之二十一(C++程序设计必知:类的静态成员)...

鸡啄米在上一讲数据和函数中讲到,函数之间共享数据也就是此函数访问彼函数的数据主要是通过局部变量、全局变量、类的数据成员、类的静态成员及友元实现的,前三个已经讲过了,这一讲鸡啄米来讲讲静态成员。静态成员包括静态数据成员和静态函数成员。

1.静态数据成员

之前讲到的类的数据成员都是一个对象一个拷贝,每个对象都有自己的数据成员的值,但有时候我们需要让某个类的所有对象共享某个数据成员,比如我们有一个学生类CStudent,其中有学号、姓名等数据成员,如果我们想要对学生人数进行统计,那么这个数据应该放在哪里呢?放在类外的某个地方的话数据的隐藏性就不好了。可能有朋友就说了,可以在类中增加一个数据成员存放学生人数,但这样就有两个坏处,第一,该类的每个对象都将有一个这个数据成员的副本,浪费内存;第二,学生人数可能在不同的对象中有不同的数,不一致了。这个时候就需要静态数据成员了。

静态数据成员存放的是类的所有对象的某个共同特征的数据,对于每个对象而言,该数据都是相同的,在内存中只存在一份。这与类的一般数据成员不同,一般数据成员会在每个对象中都有一个拷贝,每个拷贝的值可能都不一样。静态数据成员由类的所有对象共同维护和使用,这样就实现了类的对象间的数据共享。

声明静态数据成员的方式与一般数据成员不同的是,其前面要加static关键字,比如static int x;。静态数据成员具有静态生存期。它可以通过类名或对象名访问。用类名直接访问的方式为:类名::标识符。在类的声明中仅对静态数据成员进行引用性说明,就是带static的声明,必须在其文件作用域的其他地方进行定义性说明,也可以进行初始化,如果不显式初始化的话会将此静态数据成员初始化为0。

对于静态数据成员鸡啄米给大家一个例程:

#include

using namespace std;

class CStudent         // 学生类的声明

{

public:

CStudent(int nID)    { m_nID = nID; m_nCount++; }       // 构造函数

CStudent(CStudent &s);                                 // 拷贝构造函数

int GetID(){ return m_nID;}

void GetCount()       { cout<

private:

int m_nID;

static int m_nCount;                                    // 静态数据成员的引用性说明

};

CStudent::CStudent(CStudent &s)

{

m_nID = s.m_nID;

m_nCount ++;

}

int CStudent::m_nCount=0;                                       // 静态数据成员的定义性说明及初始化

int main()

{

CStudent A(6);             // 定义对象A

cout<

A.GetCount();               // 输出此时学生个数

CStudent B(A);            // 定义对象B,并用A初始化B

cout<

B.GetCount();

return 0;

}

当然学生的学号不可能一样,这里只是举个例子。类CStudent的静态数据成员m_nCount用来给学生人数计数,定义一个新的学生对象,它的值就加1。这里初始化的时候要注意,必须用类名来引用,还有就是此数据成员的访问控制属性,这里m_nCount声明为私有类型,初始化时可以直接访问,但是在主函数内就不能直接访问了。

在对象A声明时,调用构造函数,m_nCount加1,对象B声明时,调用拷贝构造函数,m_nCount又加1,两次都访问的A和B共同维护的静态数据成员,这样就实现了对象间的数据共享。上面的运行结果是:

学生A,6 学生人数:1

学生B,6 学生人数:2

e1853b932784c8171e9abcede26e291d.png

2.静态函数成员

上面的学生类中,GetCount函数用来输出静态数据成员m_nCount,我们想输出m_nCount时就要通过学生类的某个对象调用GetCount函数来实现。但是,在定义任何对象之前,m_nCount是有初始值的,那我们怎样输出这个初始值呢?因为没有定义任何对象,就没法通过对象调用GetCount。m_nCount是私有的,也不能用类名直接引用。因为m_nCount是类的所有对象共有的,那我们希望不通过对象直接用类名调用函数来显示m_nCount,这就要用到静态成员函数了。

静态成员函数跟静态数据成员一样,也是由类的所有对象所共有,由他们共同维护和使用。声明时前面也要加static关键字,比如,static void fun(void);。我们可以通过类名或对象名调用公有类型的静态成员函数,而非静态成员函数只能由对象名调用。

静态成员函数可以访问该类的静态数据成员和其他静态成员函数,如果要访问非静态数据成员,则必须将对象作为参数传递进去,然后通过传进去的对象名来访问。鸡啄米给大家举个例子:

class A

{

public:

static void f(A a);

private:

int x;

};

void A::f(A a)

{

cout<

cout<

}

所以静态成员函数访问非静态成员很麻烦,它一般用来访问全局变量和同一个类中的静态数据成员。

鸡啄米把上面学生类的GetCount函数改成静态成员函数大家看下:

#include

using namespace std;

class CStudent         // 学生类的声明

{

public:

CStudent(int nID)    { m_nID = nID; m_nCount++; }       // 构造函数

CStudent(CStudent &s);                                 // 拷贝构造函数

int GetID()                 { return m_nID;}

static void GetCount(){ cout<

private:

int m_nID;

static int m_nCount;                                    // 静态数据成员的引用性说明

};

CStudent::CStudent(CStudent &s)

{

m_nID = s.m_nID;

m_nCount ++;

}

int CStudent::m_nCount=0;                                       // 静态数据成员的定义性说明及初始化

int main()

{

CStudent A(6);                        // 定义对象A

cout<

A.GetCount();                         // 输出此时学生个数

CStudent B(A);                       // 定义对象B,并用A初始化B

cout<

CStudent::GetCount();

return 0;

}

大家可以比较的看下两个例子,学生类的声明只有一点不同,就是GetCount前加了static将其改为了静态成员函数,主函数中就可以通过类名或对象名调用静态成员函数,就像上面的A.GetCount()和CStudent::GetCount(),大家也可以把A.GetCount()改成CStudent::GetCount(),或者把CStudent::GetCount()改成B.GetCount()试下,运行结果应该是一样的。

静态成员的好处就是内存中只有一份拷贝,可以直接通过类名访问。鸡啄米今天就讲到这了,下一讲给大家讲讲友元。

除非特别注明,鸡啄米文章均为原创

2011年10月10日

作者:鸡啄米

浏览:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
啄米的资料,大家可以上官网看。这是我整理的压缩包,大家可以离线看。(这个资源还要大家积分,实在是惭愧,只因积分不够用,抱歉,体谅!) 大家要是觉得不错,可以下载我整理得另一套资源:VS2010+MFC编程入门,也是啄米的,写得不错,通俗易懂! --------------------------完整目录如下------------------- 第一部分:C++编程概述 啄米C++编程入门系列之前言 啄米C++编程入门系列之一(进制数) 啄米C++编程入门系列之二(原码、反码与补码) 第二部分:C++简单程序设计 啄米C++编程入门系列之三(VS2010的使用介绍) 啄米C++编程入门系列之四(数据型) 啄米C++编程入门系列之五(运算符和表达式) 啄米C++编程入门系列之六(算法的基本控制结构之选择结构) 啄米C++编程入门系列之七(算法的基本控制结构之循环结构) 啄米C++编程入门系列之八(自定义数据型) 第三部分:函数 啄米C++编程入门系列之九(函数的定义与调用) 啄米C++编程入门系列之十(函数的参数传递与内联函数) 啄米C++编程入门系列之十一(重载函数与函数模板) 第四部分:对象 啄米C++编程入门系列之十二(对象:面向对象设计的基本思 想和特点) 啄米C++编程入门系列之十三(对象的声明、成员的访问 控制和对象啄米C++编程入门系列之十四(对象:构造函数和析构函数) 啄米C++编程入门系列之十五(对象的组合) 啄米C++编程入门系列之十六(对象模板) 啄米C++编程入门系列之十七(对象:UML简介) 第五部分:C++程序设计必知 啄米C++编程入门系列之十八(C++程序设计必知:作用域和可见 性) 啄米C++编程入门系列之十九(C++程序设计必知:生存期) 啄米C++编程入门系列之二十(C++程序设计必知:数据和函数) 啄米C++编程入门系列二十一C++程序设计必知的静态成 员) 啄米C++编程入门系列之二十二(C++程序设计必知:友元) 啄米C++编程入门系列之二十三(C++程序设计必知:常引用、常对 象和对象的常成员) 啄米C++编程入门系列之二十四(C++程序设计必知:多文件结构和 编译预处理命令) 第六部分:数组、指针和字符串 啄米C++编程入门系列之二十五(数组、指针和字符串:数组的声 明和使用) 啄米C++编程入门系列之二十六(数组、指针和字符串:数组的存 储与初始化、对象数组、数组作为函数参数) 啄米C++编程入门系列之二十七(数组、指针和字符串:指针变量 的声明、地址相关运算--“*”和“&”) 啄米C++编程入门系列之二十八(数组、指针和字符串:指针的赋 值和指针运算) 啄米C++编程入门系列之二十九(数组、指针和字符串:指向数组 元素的指针和指针数组) 啄米C++编程入门系列之三十(数组、指针和字符串:指针用作函 数参数、指针型函数和函数指针) 啄米C++编程入门系列之三十一(数组、指针和字符串:对象指 针) 啄米C++编程入门系列之三十二(数组、指针和字符串:动态内存 分配和释放) 啄米C++编程入门系列之三十三(数组、指针和字符串:用字符数 组存放和处理字符串) 啄米C++编程入门系列之三十四(数组、指针和字符串:string ) 第七部分:继承与派生 啄米C++编程入门系列之三十五(继承与派生:概念介绍与派生 的声明) 啄米C++编程入门系列之三十六(继承与派生:派生从基继承 的过程) 啄米C++编程入门系列之三十七(继承与派生:派生对基成员 的访问控制之公有继承) 啄米C++编程入门系列之三十八(继承与派生:派生对基成员 的访问控制之保护继承与私有继承) 啄米C++编程入门系列之三十九(继承与派生:派生的构造函 数) 啄米C++编程入门系列之四十(继承与派生:派生的析构函数) 啄米C++编程入门系列之四十一(继承与派生:作用域分辨符) 啄米C++编程入门系列之四十二(继承与派生:虚基及其派生 的构造函数) 啄米C++编程入门系列之四十三(继承与派生:赋值兼容规则) 第八部分:多态性 啄米C++编程入门系列之四十四(多态性:多态的概念和型) 啄米C++编程入门系列之四十五(多态性:运算符重载的概念和规 则) 啄米C++编程入门系列之四十六(多态性:运算符重载为的成员 函数) 啄米C++编程入门系列之四十七(多态性:运算符重载为的友元 函数) 啄米C++编程入门系列之四十八(多态性:虚函数) 啄米C++编程入门系列之四十九(多态性:纯虚函数和抽象) 第九部分:异常处理 啄米C++编程入门系列之五十(异常处理) 啄米C++编程入门系列之目录和总结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值