静态成员
引入目的:实现一个类的不同对象之间数据和函数共享
谁共享:本类所有对象。
- 静态数据成员
- 用关键字static声明
- 该类的所有对象维护该成员的同一个拷贝
- 必须在类外定义和初始化,用(::)来指明所属的类。
- 静态成员函数
- 类外代码可以使用类名和作用域操作符来调用公有静态成员函数。
- 静态成员函数只能引用属于该类的静态数据成员或静态成员函数。访问非静态数据成员,必须通过参数传递方式得到对象名,通过对象名访问。
1. 静态数据成员
为何需要静态数据成员?
例 静态数据成员的引例
#include<iostream.h>
#include<string.h>
class Student {
public:
Student(char *name1,char *stu_no1,float score1);
~Student();
void show(); // 输出姓名、 学号和成绩
void show_count_sum_ave(); // 输出学生人数
private:
char *name; // 学生姓名
char *stu_no; // 学生学号
float score; // 学生成绩
int count;
float sum;
float 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: "<<name;
cout<<"\n stu_no: "<<stu_no;
cout<<"\n score: "<<score;
}
void Student::show_count_sum_ave()
{
cout<<"\n count: "<<count;
cout<<"\n sum: "<<sum;
cout<<"\n ave: "<<ave;
}
void main()
{
Student stu1("Liming","990201",90);
stu1.show();
stu1.show_count_sum_ave();
Student stu2("Zhanghao","990202",85);
stu2.show();
stu2.show_count_sum_ave();
}
如何定义静态数据成员?
在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。
静态数据成员特点?
- 与一般的数据成员不同,无论建立多少个类的对象,都只有一个静态数据的拷贝。从而实现了同一个类的不同对象之间的数据共享。
- 它不因对象的建立而产生,也不因对象的析构而删除。它是类定义的一部分,所以使用静态数据成员不会破坏类的隐蔽性。
- 在类的声明中只能声明静态数据成员的存在。由于类的声明是抽象的,静态数据成员的初始化需要在类的外部进行, 通过类名对它进行访问。
静态数据成员初始化的格式
<数据类型> <类名> ∷ <静态数据成员名> = <值> ; 值> 静态数据成员名> 类名> 数据类型>
- 初始化时不加该成员的访问权限控制符private,public等。
- 初始化时使用作用域运算符来标明它所属的类,因此,静态数据成员是类的成员,而不是对象的成员。
引用静态数据成员时,采用如下格式:
<类名> ∷ <静态成员名>静态成员名> 类名>
- 如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。
例3.15 静态数据成员的使用引例
#include<iostream.h>
#include<string.h>
class Student {
public:
Student(char *name1,char *stu_no1,float score1);
~Student();
void show(); // 输出姓名、 学号和成绩
void show_count_sum_ave(); // 输出学生人数
private:
char *name; // 学生姓名
char *stu_no; // 学生学号
float score; // 学生成绩
static int count; // 静态数据成员,统计学生人数
static float sum; // 静态数据成员,统计总成绩
static float 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: "<<name;
cout<<"\n stu_no: "<<stu_no;
cout<<"\n score: "<<score;
}
void Student::show_count_sum_ave()
{
cout<<"\n count: "<<count; // 输出静态数据成员count
cout<<"\n sum: "<<sum; // 输出静态数据成员sum
cout<<"\n ave: "<<ave; // 输出静态数据成员ave
}
int Student::count=0; // 静态数员count初始化
float Student::sum=0.0; // 静态数员sum初始化
float Student::ave=0.0; // 静态数员ave初始化
void main()
{
Student stu1("Liming","990201",90);
stu1.show();
stu1.show_count_sum_ave();
Student stu2("Zhanghao","990202",85);
stu2.show();
stu2.show_count_sum_ave();
}
如何使用静态数据成员?
- (1)静态数据成员的定义与一般数据成员相似,但前面要加上static关键词。
static 数据类型 数据成员名;
- (2)静态数据成员的初始化与一般数据成员不同。
- 初始化格式: 数据类型 类名::静态数据成员=值;
- 初始化位置:定义对象之前,一般在类定义后,main()前进行。
- (3) 访问方式(只能访问公有静态数据成员)
- 可用类名访问: 类名::静态数据成员
- 也可用对象访问:
- 对象名.静态数据成员
- 对象指针->静态数据成员
【例3.16】 公有静态数据成员的访问
#include<iostream.h>
class myclass{
public:
static int i;
int geti()
{ return i;}
};
int myclass∷i=0; // 初始化,不必在前面加static
main()
{
myclass∷i=200;
myclass ob1,ob2;
cout<<"ob1.i="<<ob1.geti()<<endl;
cout<<"ob2.i="<<ob2.geti()<<endl;
ob1.i=300; // 对象进行访问
cout<<"ob1.i="<<ob1.geti()<<endl;
cout<<"ob2.i="<<ob2.geti()<<endl;
return 0;
}
(4) 私有静态数据成员不能被类外部函数访问,也不能用对象进行访问。
(5) 支持静态数据成员的一个主要原因是可以不必使用全局变量。静态数据成员的主要用途是定义类的各个对象所公用的数据。
【例3.17】 静态数据成员和一般数据成员的不同
#include<iostream.h>
class Student{
public:
Student() // 构造函数
{
++count; // 每创建一个学生对象,学生数加1
StudentNo=count; // 给当前学生的学号赋值
}
void print() // 成员函数,显示学生的学号和当前学生数
{
cout<<"Student"<<StudentNo<<" ";
cout<<"count="<<count<<endl;
}
private:
static int count; // 静态数据成员count,统计学生的总数
int StudentNo; // 普通数据成员,用于表示每个学生的学号
};
int Student::count=0;
main()
{
Student Student1;
Student1.print();
cout<<"-----------\n";
Student Student2;
Student1.print();
Student2.print();
cout<<"-----------\n";
Student Student3;
Student1.print();
Student2.print();
Student3.print();
cout<<"-----------\n";
Student Student4;
Student1.print();
Student2.print();
Student3.print();
Student4.print();
return 0;
}
执行结果为:
Student1 count=1
------------
Student1 count=2
Student2 count=2
------------
Student1 count=3
Student2 count=3
Student3 count=3
------------
Student1 count=4
Student2 count=4
Student3 count=4
Student4 count=4
2. 静态成员函数
- 可以通过定义和使用静态成员函数来访问静态数据成员。
- 所谓静态成员函数就是使用static关键字声明函数成员。同静态数据成员一样,静态成员函数也属整个类, 由同一个类的所有对象共同维护,为这些对象所共享。
- 静态成员函数作为成员函数,它的访问属性可以受到类的严格控制。对公有静态成员函数,可以通过类名或对象名来调用;而一般的非静态公有成员函数只能通过对象名来调用。
- 静态成员函数可以直接访问该类的静态数据成员和函数成员;而访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问。
定义静态成员函数的格式如下
static 返回类型 静态成员函数名(参数表);
使用目的: 在对象建立之前处理静态数据成员或全局变量
使用公有静态成员函数的一般格式
与静态数据成员类似,使用公有静态成员函数的一般格式有如下几种:
- 类名::静态成员函数名(实参表)
- 对象. 静态成员函数名(实参表)
- 对象指针->静态成员函数名(实参表)
例3.18静态成员函数来访问静态数据成员
#include<iostream.h>
#include<string.h>
class Student {
private:
char *name;
char *stu_no;
float score;
static int count;
static float sum;
public:
Student(char *name1,char *stu_no1,float score1);
~Student();
void show();
static void show_count_sum();
};
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; // 累加总成绩
}
Student::~Student()
{
delete []name;
delete []stu_no;
--count;
sum=sum-score;
}
void Student::show()
{
cout<<"\n name: "<<name;
cout<<"\n stu_no: "<<stu_no;
cout<<"\n score: "<<score;
}
void Student::show_count_sum() // 静态成员函数
{
cout<<"\n count: "<<count; // 输出静态数据成员
cout<<"\n sum: "<<sum; // 输出静态数据成员
}
int Student::count=0; // 静态数据成员初始化
float Student::sum=0.0; // 静态数据成员初始化void main()
{
Student stu1("Liming","990201",90);
stu1.show();
Student::show_count_sum(); // 使用类名访问静态成员函数
Student stu2("Zhanghao","990202",85);
stu2.show();
stu2.show_count_sum(); // 使用对象stu2访问静态成员函数
}
使用静态成员函数时须注意
- (1) 静态成员函数可以定义成内嵌的,也可以在类外定义,在类外定义时不能用static前缀。
- (2) 静态成员函数主要用来访问全局变量或同一个类中的静态数据成员。特别是,当它与静态数据成员一起使用时,达到了对同一个类中对象之间共享数据进行维护的目的。
- (3) 私有静态成员函数不能被类外部函数和对象访问。
- (4) 使用静态成员函数的一个原因是,可以用它在建立任何对象之前处理静态数据成员。这是普通成员函数不能实现的。
- (5) 静态成员函数中没有指针this,所以静态成员函数不访问类中的非静态数据成员,若确实需要则只能通过对象名(作为参数)访问。
【例3.19】 静态成员函数访问非静态数据成员
#include<iostream.h>
class small_cat {
public:
small_cat(double w)
{
weight=w;
total_weight+=w;
total_number++;
}
static void display(small_cat& w)//访问非静态成员
{ cout<<"The small_cat weights "<<w.weight<<" kg\n";}
static void total_disp() //访问静态成员
{
cout<<total_number<<" small_cat total_weight ";
cout<<total_weight<<"kg "<<endl;
}
private:
double weight;
static double total_weight;
static double total_number;
};
double small_cat∷total_weight=0;
double small_cat∷total_number=0;
int main()
{
small_cat w1(0.9), w2(0.8), w3(0.7);
small_cat∷display(w1);
small_cat∷display(w2);
small_cat∷display(w3);
small_cat∷total_disp();
return 0;
}
通过普通指针访问静态成员
例3.20 通过指针访问类的静态数据成员
#include<iostream.h>
class myclass {
public:
myclass() // 构造函数,每定义一个对象, 静态数据成员i加1
{ ++i; }
static int i; // 声明静态数据成员i
};
int myclass::i=0; // 静态数据成员i初始化,不必在前面加static
main()
{
int *count=&myclass::i;
myclass ob1,ob2,ob3,ob4;
cout<<“ myclass::i= ”<<*count<<endl;
return 0;
}
【例3.21】 通过指针访问类的静态成员函数
#include<iostream.h>
class myclass {
public:
myclass()
{ ++i; }
static int geti()
{ return i; }
private:
static int i;
};
int myclass::i=0;
main()
{
int (*get)()=myclass::geti;
myclass ob1,ob2,ob3;
cout<<"myclass∷i="<<(*get)()<<endl;
return 0;
}