C++学习笔记1——静态成员

来源:互联网 发布:stc8 串口发送数据 编辑:程序博客网 时间:2024/05/16 10:30

静态成员的提出是为了实现一个类的多个对象之间的数据共享。静态成员包括静态数据成员和静态函数成员。
一.静态数据成员
1.先举一个出现错误的代码来作为引例引出静态成员。

#include<iostream>#include<string.h>using namespace std;class Student{    private:    char *name;    char *stu_no;    float score;    int count;    float sum;    float ave;    public:    Student(char *name1,char *stu_no1,float score1);    ~Student();    void show();    void show_count_sum_ave();};Student::Student(char *name1,char *stu_no1,float score1){    name=new char[strlen(name1)+1];    strcpy(name,name1);    stu_no=new char[strlen(stu_no1)+1];    strcpy(stu_no,stu_no1);    score=score1;    ++count;    sum=sum+score;    ave=sum/count;}Student::~Student(){    delete []name;    delete []stu_no;    --count;    sum=sum-score;}void Student::show(){    cout<<"\n姓名:"<<name;    cout<<"\n学号:"<<stu_no;    cout<<"\n成绩:"<<score;}void Student::show_count_sum_ave(){    cout<<"\n学生人数:"<<count;    cout<<"\n平均成绩:"<<ave;}int main(void){    Student stu1("liangxueli","04141108",90);    stu1.show();    stu1.show_count_sum_ave();    cout<<"---------------------------------\n";    Student stu2("lijunyi","04141105",80.2);    stu2.show();    stu2.show_count_sum_ave();    return 0;}

错误的输出结果为:

姓名:liangxueli学号:04141108成绩:90学生人数:1             //错误结果平均成绩:90            //错误结果---------------------------------姓名:lijunyi学号:04141105成绩:80.2学生人数:1             //错误结果平均成绩:80.2          //错误结果

【分析】本例子的设计思想是,希望每定义一个对象,调用一次构造函数,使数据成员count加1从而累计学生人数,同时用数据成员sum累加学生成绩,求出学生的累加成绩,用数据成员ave计算平均成绩。但是这个例子的运行结果是错误的。其原因是,一个学生对象的count、sum和ave仅仅属于这个学生对象,而不是所有学生对象所共享的,因此它们不能表示所有学生的人数、累加成绩和平均成绩。为了使count、sum和ave被所有的对象共享,可以有两种解决方案。第一个方法是,将count、sum和ave说明为 全局变量。但是,使用全局变量会带来不安全性,并且破坏了面向对象程序设计的信息隐蔽技术,与面向对象的封装性特点是矛盾的。第二个方法就是使用静态数据成员——在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。与一半的数据成员不同,无论建立多少个类的对象,都只有一个静态数据成员的拷贝。从而实现了一个类的不同对象之间的数据共享。
2.静态数据成员的定义如下:
static 数据类型 数据成员名;
将上例中count、sum和ave改为静态数据成员来处理,过程及结果如下:

#include<iostream>#include<string.h>using namespace std;class Student{    private:    char *name;    char *stu_no;    float score;    static int count;    static float sum;    static float ave;    public:    Student(char *name1,char *stu_no1,float score1);    ~Student();    void show();    void show_count_sum_ave();};Student::Student(char *name1,char *stu_no1,float score1){    name=new char[strlen(name1)+1];    strcpy(name,name1);    stu_no=new char[strlen(stu_no1)+1];    strcpy(stu_no,stu_no1);    score=score1;    ++count;    sum=sum+score;    ave=sum/count;}Student::~Student(){    delete []name;    delete []stu_no;    --count;    sum=sum-score;}void Student::show(){    cout<<"\n姓名:"<<name;    cout<<"\n学号:"<<stu_no;    cout<<"\n成绩:"<<score;}void Student::show_count_sum_ave(){    cout<<"\n学生人数:"<<count;    cout<<"\n平均成绩:"<<ave;}int Student::count=0;float Student::sum=0.0;float Student::ave=0.0;int main(void){    Student stu1("liangxueli","04141108",90);    stu1.show();    stu1.show_count_sum_ave();    cout<<"---------------------------------\n";    Student stu2("lijunyi","04141105",80);    stu2.show();    stu2.show_count_sum_ave();    return 0;}(PS:出现了“error: stray ‘\357′ in program”的错误,原因:在程序中输入了全角字符)

正确运行结果:

姓名:liangxueli学号:04141108成绩:90学生人数:1平均成绩:90---------------------------------姓名:lijunyi学号:04141105成绩:80学生人数:2平均成绩:85

3.说明:
1>静态数据成员的定义与普通数据成员相似,但前面要加上static关键字;
2>静态数据成员的初始化与普通数据成员不同。静态数据成员初始化应在类外单独进行,而且应在定义对象之前进行,一般在主函数main之前,类声明之后的特殊地带为它提供定义和初始化。初始化的格式如下:
数据类型 类名::静态数据成员名=初始值;
注意:这个时候在数据成员名前面不要加static
3>静态数据成员属于类(准确说是属于类对象的集合),而不像普通数据成员那样属于某一个对象,因此可以使用类名:: 访问静态的数据成员,例如:

#include<iostream>#include<string.h>using namespace std;class myclass{    public:    static int i;    int geti()    {return i;}};int myclass ::i=0;int main(void){    myclass::i=200;//公有静态数据成员可以在对象定义之前被访问    myclass ob1,ob2;    cout<<"successful!\n"<<endl;    return 0;}

4>静态数据成员和静态变量一样,是在编译时创建并初始化。它在该类的任何对象被建立之前就存在,因此,公有的静态数据成员可以在对象定义之前被访问(一般给静态数据成员初始化赋值的时候属于定义对象之前的访问),定义对象后,公有的静态数据成员也可以通过对象进行访问:
对象名.静态数据成员名
对象指针->静态数据成员名
5>私有静态数据成员不能在类外直接访问,必须通过公有的成员函数函数访问;
6>静态数据成员主要用作类的所有对象公有的数据,如统计总数、平均数等。

二.静态成员函数

1.在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数属于整个类,是该类所有对象共享的成员函数,而不属于内种某个对象,定义静态成员函数的格式如下:
static 返回类型 静态成员函数名(参数);
2.与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:
类名::静态成员函数名(实参)
对象.静态成员函数名(实参)
对象指针->静态成员函数名(实参)

下面是静态成员函数访问静态数据成员的例子:

#include<iostream>using namespace std;class Small_cat{    private:    double weight;    static double total_weight;    static double total_number;    public:    Small_cat(double w);    void display();    static void total_disp();};Small_cat::Small_cat(double w){    weight=w;    total_weight+=w;    total_number++;}void Small_cat::display(){    cout<<"这只小猫的重量是:"<<weight<<"千克\n";}void Small_cat::total_disp(){    cout<<total_number<<"只小猫的总重量是:";    cout<<total_weight<<"千克"<<endl;}double Small_cat::total_weight=0;double Small_cat::total_number=0;int main(void){    Small_cat w1(0.5),w2(0.6),w3(0.4);    w1.display();    w2.display();    w3.display();    Small_cat::total_disp();    return 0;}

运行结果如下:

这只小猫的重量是:0.5千克这只小猫的重量是:0.6千克这只小猫的重量是:0.4千克3只小猫的总重量是:1.5千克

【分析】上面的程序中声明了一个类Small_cat,在类中定义了两个静态数据成员total weight和total _number分别用来累计小猫的重量和累计小猫的只数;在类中还定义了一个静态成员函数total 用来显示小猫的只数和总重量。每当定义了一个类Small _cat的对象时,就通过调用构造函数把每只猫的的重量weight加到总重量total _weight上,同时对象计数器total _number加1,即累计小猫的只数。
3.说明
1>一般情况下,静态函数成员主要用来访问静态数据成员。当它与静态数据成员一起使用时,达到了对同一个类中对象之间共享数据的目的;
2>私有静态成员函数不能做类外部的函数和对象访问;
3>使用静态成员函数的一个原因是,可以用它在建立任何对象之前调用静态成员函数,以处理静态数据成员,这是普通成员函数不能实现的功能。例如:

int main(void){ Small_cat::total_disp();//可以用它在建立任何对象之前调用静态成员函数 Small_cat w1(0.5),w2(0.6),w3(0.4);     .     .     .}

4>编译系统将静态成员函数限定为内部连接,也就是说,与现行文件相连接的其他文件中的同名函数不会与该函数发生冲突,维护了该函数使用的安全性,这是使用静态成员函数的另一个原因;
5>静态成员函数是类的一部分,不是对象的一部分。如果要在类外调用公有的静态成员函数,使用如下格式:
类名::静态成员函数名()
如上例中的Small_cat::total_disp();
当然如果已经定义了这个类的对象,就用对象引用函数的方法实现就可以;
6>静态成员函数与非静态成员函数的重要区别是:
非静态成员函数有this指针,而静态成员函数没有this指针;
静态成员函数可以直接访问本类中的静态数据成员,因为静态数据成员同样是属于类的,可以直接访问。一般而言,静态成员函数不访问类中的非静态成员,例如:

cout<<"一只小猫的重量是:"<<weight<<"千克\n";//不合法,weight是非静态数据成员cout<<"小猫的总重量是:"<<total_weight<<"千克"<<endl;//合法,total_weight是静态数据成员

若确实需要访问非静态数据成员,静态成员函数只能通过对象名(对象指针、对象引用)访问该对象的非静态成员。如把display函数定义为静态成员函数时,可将对象的引用作为函数参数,将它定义为:

static void display(small_cat &w){cout<<"这只小猫的重量是:"<<w.weight<<"千克\n";}
0 0