首页
学习
活动
专区
圈层
工具
发布
30 篇文章
1
《挑战30天C++入门极限》C++的iostream标准库介绍(1)
2
《挑战30天C++入门极限》C++的iostream标准库介绍(2)
3
《挑战30天C++入门极限》C++的iostream标准库介绍(3)
4
《挑战30天C++入门极限》C++运算符重载赋值运算符
5
《挑战30天C++入门极限》C++运算符重载函数基础及其值返回状态
6
《挑战30天C++入门极限》对C++递增(增量)运算符重载的思考
7
《挑战30天C++入门极限》类的分解,抽象类与纯虚函数的需要性
8
《挑战30天C++入门极限》C++中利用构造函数与无名对象简化运算符重载函数
9
《挑战30天C++入门极限》C++中类的多态与虚函数的使用
10
《挑战30天C++入门极限》C++运算符重载转换运算符
11
《挑战30天C++入门极限》图例实解:C++中类的继承特性
12
《挑战30天C++入门极限》C++类的继承与多重继承的访问控制
13
《挑战30天C++入门极限》图文例解C++类的多重继承与虚拟继承
14
《挑战30天C++入门极限》理解C++面向对象程序设计中的抽象理论
15
《挑战30天C++入门极限》C++面向对象编程入门:构造函数与析构函数
16
《挑战30天C++入门极限》C++类对象的复制-拷贝构造函数
17
《挑战30天C++入门极限》C++类静态数据成员与类静态成员函数
18
《挑战30天C++入门极限》入门教程:实例详解C++友元
19
《挑战30天C++入门极限》C++面向对象编程入门:类(class)
20
《挑战30天C++入门极限》新手入门:C++中的函数重载
21
《挑战30天C++入门极限》新手入门:C/C++中的结构体
22
《挑战30天C++入门极限》C/C++中字符串常量的不相等性及字符串的Copy
23
《挑战30天C++入门极限》新手入门:C++中堆内存(heap)的概念和操作方法
24
《挑战30天C++入门极限》C/C++中字符指针数组及指向指针的指针的含义
25
《挑战30天C++入门极限》C/C++中结构体(struct)知识点强化
26
《挑战30天C++入门极限》新手入门:关于C++中的内联函数(inline)
27
《挑战30天C++入门极限》新手入门:C/C++中枚举类型(enum)
28
《挑战30天C++入门极限》新手入门:C++中布尔类型
29
《挑战30天C++入门极限》新手入门:C/C++中数组和指针类型的关系
30
《挑战30天C++入门极限》新手入门:C++下的引用类型

《挑战30天C++入门极限》C++类静态数据成员与类静态成员函数

代码语言:javascript
复制






 

C++类静态数据成员与类静态成员函数

  在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢? 

  这个问题便是本章的重点: 


  声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。 


  下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。 


  以下程序我们来做一个模拟访问的例子,在程序中,每建立一个对象我们设置的类静态成员变自动加一,代码如下:

#include <iostream>  
using namespace std;  
  
class Internet  
{  
public:  

    Internet(char *name,char *address)  
    {  

        strcpy(Internet::name,name);  

        strcpy(Internet::address,address);  
        count++;  
    }  
    static void Internet::Sc()//静态成员函数  
    {  
        cout<<count<<endl;  

    }  
    Internet &Rq();  
public:  

    char name[20];  
    char address[20];  
    static int count;//这里如果写成static int count=0;就是错误的  
};  
  

Internet& Internet::Rq()//返回引用的成员函数  
{  

    return *this;  
}  

  
int Internet::count = 0;//静态成员的初始化  
void vist()  
{  

    Internet a1("中国软件开发实验室","www.cndev-lab.com");  

    Internet a2("中国软件开发实验室","www.cndev-lab.com");  
}  
void fn(Internet &s)  
{  
    cout<<s.Rq().count;  
}  

void main()  
{  

    cout<<Internet::count<<endl;//静态成员值的输出  

    vist();  
    Internet::Sc();//静态成员函数的调用  

    Internet b("中国软件开发实验室","www.cndev-lab.com");  
    Internet::Sc();  

    fn(b);  
    cin.get();  
}

  上面代码我们用了几种常用的方式建立对象,当建立新对象并调用其构造函数的时候,静态成员cout便运行加1操作,静态成员的初始化应该在主函数调用之前,并且不能在类的声明中出现,通过运行过程的观察我们发现,静态成员count的状态并不会随着一个新的对象的新建而重新定义,尽而我们了解到静态成员函数由于与对象无关系,所以在其中是不能对类的普通成员进行直接操作的。 

  如果上面的 
static void Internet::Sc()修改成为:

static void Internet::Sc()//静态成员函数  
{  

    cout<<name<<endl;//错误  
    cout<<count<<endl;  
} 

  静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。

  根据类静态成员的特性我们可以简单归纳出几点,静态成员的使用范围: 

  1.用来保存对象的个数。 


  2.作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态,等等。 


  3.存储链表的第一个或者最后一个成员的内存地址。 


  为了做一些必要的练习,深入的掌握静态对象的存在的意义,我们以前面的结构体的教程为基础,用类的方式描述一个线性链表,用于存储若干学生的姓名,代码如下:

#include <iostream>  
using namespace std;  
  
class Student  
{  
public:  

    Student (char *name);  
    ~Student();  

public:  
    char name[30];  
    Student *next;  
    static Student *point;  
};  
  

Student::Student (char *name)  
{  

    strcpy(Student::name,name);  
    this->next=point;  
    point=this;  
}  
  
Student::~Student ()//析构过程就是节点的脱离过程  
{  
    cout<<"析构:"<<name<<endl;  
  

    if(point==this)  

    {  
        point=this->next;  

        cin.get();  
        return;  
    }  
    for(Student *ps=point;ps;ps=ps->next)  
    {  

        if(ps->next==this)  
        {  
        cout<<ps->next<<"|"<<this->next<<endl;  
        ps->next=next;//=next也可以写成this->next;  
        cin.get();  
        return;  

        }  
    }  
    cin.get();  
}  

  
Student* Student::point=NULL;  
void main()  
{  
    Student *c = new Student("marry");  

    Student a("colin");  
    Student b("jamesji");  
    delete c;  
    Student *fp=Student::point;  
    while(fp!=NULL)  
    {  
        cout<<fp->name<<endl;  

        fp=fp->next;  
    }  
    cin.get();  
}

  从上面的代码来看,原来单纯结构化编程需要的一个链表进入全局指针在这里被类的静态成员指针所替代(类的静态成员完全可以替代全局变量),这个例子的理解重点主要是要注意观察类成员的析构顺序,通过对析构顺序的理解,使用析构函数来进行节点的脱链操作。

 




 




 











下一篇
举报
领券