您的位置:首页 > 编程语言 > C语言/C++

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

2016-03-22 17:33 555 查看
静态成员的提出是为了实现一个类的多个对象之间的数据共享。静态成员包括静态数据成员和静态函数成员。

一.静态数据成员

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";}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: