3.7.1 静态数据成员
对象是类的一个实例,每个对象都具有自己的数据成员。例如,学生类张三或李四都具有自
己的学号,姓名和平均成绩。在实际使用时,常常还需要一些其他的数据项,比如学生人数、
总成绩、平均成绩。但是如果把这些数据项作为普通的数据成员来处理,将会产生错误。下
面通过例子来说明:

 例3.  静态数据成员的引例 

#include<iostream>
#include<string>
using namespace std;
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; //定义普通数据成员count
float sum; //定义普通数据成员sum
float ave; //定义普通数据成员ave
};
Student::Student(char* name1,char* stu_no1,float score1)
{
name = new char[strlen(name1)+];//为学生姓名动态分配一个空间,并让name指向数组的首地址
strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制name1所指向的内容
stu_no = new char[strlen(stu_no1)+];
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<<"姓名:"<<name<<endl;
cout<<"学号:"<<stu_no<<endl;
cout<<"成绩:"<<score<<endl;
}
void Student::show_count_sum_ave()
{
cout<<"学生人数:"<<count<<endl;
cout<<"总成绩:"<<sum<<endl;
cout<<"平均成绩:"<<ave<<endl;
}
int main()
{
Student stu1("李明","",90.0);
stu1.show();
stu1.show_count_sum_ave();
cout<<"------------------------"<<endl; Student stu2("王勇","",92.5);
stu2.show();
stu2.show_count_sum_ave(); return ;
}
/*
运行结果发现:学生人数、总成绩、平均成绩都是错误的。 其原因:一个学生对象的count、sum、ave仅仅属于这个学生对象,而不是所有学生对象
所共享的,因此它们不能表示所有学生的人数、总成绩、平均成绩。 解决办法:将count、sum、ave这个普通数据成员设为静态的数据成员,让所有的对象共享。 格式为: static 数据类型 数据成员
*/

将上面的例子改为静态的数据成员来处理,如下....

例3.29 静态数据成员的使用

#include<iostream>
#include<string>
using namespace std;
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; //定义静态数据成员count
static float sum; //定义静态数据成员sum
static float ave; //定义静态数据成员ave
};
Student::Student(char* name1,char* stu_no1,float score1)
{
name = new char[strlen(name1)+];//为学生姓名动态分配一个空间,并让name指向数组的首地址
strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制name1所指向的内容
stu_no = new char[strlen(stu_no1)+];
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<<"姓名:"<<name<<endl;
cout<<"学号:"<<stu_no<<endl;
cout<<"成绩:"<<score<<endl;
}
void Student::show_count_sum_ave()
{
cout<<"学生人数:"<<count<<endl;
cout<<"总成绩:"<<sum<<endl;
cout<<"平均成绩:"<<ave<<endl;
}
int Student::count=; //对静态数据成员count进行初始化
float Student::sum=; //对静态数据成员sum进行初始化
float Student::ave=; //对静态数据成员ave进行初始化
int main()
{
Student stu1("李明","",90.0);
stu1.show();
stu1.show_count_sum_ave();
cout<<"------------------------"<<endl; Student stu2("王勇","",92.5);
stu2.show();
stu2.show_count_sum_ave(); return ;
}

说明:
(1)静态数据成员的定义与普通数据成员相似,但前面要加上static关键字。
static int count; //静态数据成员,用于统计学生人数
static float score; //静态数据成员,用于统计学生成绩
static float ave; //静态数据成员,用于统计学生平均分

(2)静态数据成员的初始化与普通数据成员不同。静态数据成员初始化应在类外单独进行,
而且应定义对象之前进行。一般在主函数main之前,类声明之后的特殊地带为它提供
定义和初始化。初始化格式如下:

数据类型 类名::静态数据成员=初始值

int Student::count=0;
int Student::sum=0;
float Student::ave=0;

注意:这时在数据成员的前面不要加static

(3)静态数据成员属于类(准确的说,是属于类的对象的集合),而不像普通函数那样属于
某一对象,因此可以使用"::"访问静态的数据成员。

用类名访问静态数据成员的格式如下:

类名::静态数据成员
例如上面的Student::count、Student::sum、Student::ave

(4)静态数据成员与静态变量一样,是在编译时创建并初始化。它在该类的任何对象被建立
之前就存在。因此,共有的数据成员可以在对象被定义之前被访问。对象建立后,共有
的静态数据成员也可以被对象进行访问。

用对象访问静态数据成员的格式如下:

对象.静态数据成员
对象指针.静态数据成员

例1:通过对象访问静态数据成员

#include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(string name1,string stu_no1,float score1);//(char* name1,char* stu_no1,float score1)
~Student();//声明析构函数
void show();
void show_count_sum_ave();
private:
string name; //学生姓名
string stu_no;//学生学号
// char* name;
// char* stu_no;
float score;
static int count; //定义静态数据成员count
static float sum; //定义静态数据成员sum
static float ave; //定义静态数据成员ave
};
Student::Student(string name1,string stu_no1,float score1)//(char* name1,char* stu_no1,float score1)
{
//name = new char[strlen(name1)+1];//为学生姓名动态分配一个空间,并让name指向数组的首地址
// strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制name1所指向的内容
// stu_no = new char[strlen(stu_no1)+1];
// strcpy(stu_no,stu_no1);
score = score1;
name = name1;
stu_no = stu_no1;
count++;
sum = sum+score;
ave = sum/count;
}
Student::~Student()
{
//delete []name; //释放空间
// delete []stu_no;//释放空间
// --count;
// sum = sum-score;
}
void Student::show()
{
cout<<"姓名:"<<name<<endl;
cout<<"学号:"<<stu_no<<endl;
cout<<"成绩:"<<score<<endl;
}
void Student::show_count_sum_ave()
{
cout<<"学生人数:"<<count<<endl;
cout<<"总成绩:"<<sum<<endl;
cout<<"平均成绩:"<<ave<<endl;
}
int Student::count=; //对静态数据成员count进行初始化
float Student::sum=; //对静态数据成员sum进行初始化
float Student::ave=; //对静态数据成员ave进行初始化
int main()
{
Student stu1("李明","",90.0);
stu1.show();
stu1.show_count_sum_ave();
cout<<"------------------------"<<endl; Student stu2("王勇","",92.5);
stu2.show();
stu2.show_count_sum_ave(); return ;
}

例2:通过指针对象访问静态数据成员

#include<iostream>
#include<string>
using namespace std;
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; //定义静态数据成员count
static float sum; //定义静态数据成员sum
static float ave; //定义静态数据成员ave
};
Student::Student(char* name1,char* stu_no1,float score1)
{
name = new char[strlen(name1)+];//为学生姓名动态分配一个空间,并让name指向数组的首地址
strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制name1所指向的内容
stu_no = new char[strlen(stu_no1)+];
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<<"姓名:"<<name<<endl;
cout<<"学号:"<<stu_no<<endl;
cout<<"成绩:"<<score<<endl;
}
void Student::show_count_sum_ave()
{
cout<<"学生人数:"<<count<<endl;
cout<<"总成绩:"<<sum<<endl;
cout<<"平均成绩:"<<ave<<endl;
}
int Student::count=; //对静态数据成员count进行初始化
float Student::sum=; //对静态数据成员sum进行初始化
float Student::ave=; //对静态数据成员ave进行初始化
int main()
{
Student stu1("李明","",90.0),*p1;
// stu1.show();
// stu1.show_count_sum_ave();
p1 = &stu1;
//p1->show();
//p1->show_count_sum_ave();
(*p1).show();
(*p1).show_count_sum_ave();
cout<<"------------------------"<<endl; Student stu2("王勇","",92.5),*p2;
p2 = &stu2;
//p2->show();
//p2->show_count_sum_ave();
(*p2).show();
(*p2).show_count_sum_ave(); return ;
}

例3.30 公有静态数据成员的访问(在类外可以直接访问)
(私有静态数据成员不能在类外直接访问,必须通过公有的成员函数访问。)

#include<iostream>
using namespace std;
class Myclass{
public:
static int i;
int get()
{
return i;
}
};
int Myclass::i=;
int main()
{
Myclass::i=; //公有静态数据成员可通过对象进行访问
Myclass obj1,obj2;
cout<<"obj1.i="<<obj1.get()<<endl;
cout<<"obj2.i="<<obj2.get()<<endl; obj1.i=;//公有静态数据成员通过对象进行访问并进行重赋值 cout<<"obj1.i="<<obj1.get()<<endl;
cout<<"obj2.i="<<obj2.get()<<endl; return ;
}
/* 运行结果为: obj1.i=200
obj2.i=200
obj1.i=300
obj2.i=300
解析:从本例中可以看出,由于静态数据成员只有一个值,所以不论用那个对象进行访问
,所得的结果是一样的。所以,从这个意义上讲,静态数据成员也是类的公共数据
成员,是对象的共有数据项。 c++支持静态数据成员的一个重要原因是不必使用全局变量。因为全局变量违反了面向对象程序
设计的封装性特点。静态数据成员主要作用于类的所有对象的公用的数据,如统计总数、平均数等.... */

3.7.2 静态成员函数

在类定义中,前面有static说明的成员函数称之为静态成员函数。静态成员函数属于整个
类,是该类所有对象共享的成员函数,而不属于类中的某个对象。

定义静态成员函数的格式如下:
static 返回类型 静态数据成员函数(参数表);

与静态数据成员类似,调用公有静态成员函数的一般格式有如下三种:
1、类名.静态成员函数(实参表)
2、对象.静态成员函数(实参表)
3、对象指针->静态成员函数(实参表)

//例3.31  静态成员函数访问静态数据成员。
#include<iostream>
using namespace std;
class Small_cat{
public:
Small_cat(double w); //声明构造函数
void display(); //声明非静态成员函数
static void total_disp(); //声明非静态成员函数
private:
double weight; //定义普通数据成员,表示一只小猫的重量
static double total_weight; //定义静态数据成员,用于累计小猫的重量
static double total_number; //定义静态数据成员,用于累计小猫的数量
};
Small_cat::Small_cat(double w) //定义构造函数
{
weight = w;
total_weight += w; //累计小猫的重量
total_number++; //累加小猫的数量
}
void Small_cat::display()
{
cout<<"这只小猫的重量是:"<<weight<<"千克"<<endl;
}
void Small_cat::total_disp()
{
cout<<total_number<<"只小猫的重量是:"<<total_weight<<"千克"<<endl;
}
double Small_cat::total_weight=; //对私有的静态数据成员进行初始化
double Small_cat::total_number=; //对私有的静态数据成员进行初始化
int main()
{
Small_cat::total_disp(); //对象创建之前,通过类名::调用静态成员函数 Small_cat w1(0.5),w2(0.6),w3(0.4),*p; //创建三个小猫对象并进行初始化,并另外定义一个指针p
w1.display(); //通过对象调用非静态成员函数
w2.display();
w3.display();
cout<<endl; p = &w1;
(*p).total_disp(); //通过指针调用静态成员函数
p->total_disp();
cout<<endl; Small_cat::total_disp(); //通过类名::调用静态成员函数
w1.total_disp();//通过对象调用静态成员函数
w2.total_disp();
w2.total_disp(); return ;
}

对静态成员函数的使在作几点说明:
1、一般情况下,静态函数成员主要用来访问静态数据成员。当它与静态数据成员一起使用
时,达到了对同一类中对象之间共享数据的目的。

2、私有静态成员函数不能做类外部的函数和对象访问。

3、使用静态成员函数的一个原因是,可以用它在建立任何对象之前调用静态成员函数,以处理
静态数据成员,这是普通成员函数不能实现的功能。

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

4、编译系统将静态成员函数限定为内部连接,也就是说,与现行文件相连接的其他文件
中的同名函数不会与该函数发生冲突,维护了该函数使用的安全性,这是使用静态成员
函数的另一个原因。

5、静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公有静态成员函数,
使用格式是: 类名::静态成员函数

例如上述中Small_cat::disp();

当然如果定义了这个类的对象,也可以用对象调用静态成员函数

如 w1.cat::disp();

6、静态成员函数和非静态成员函数的区别是:非静态成员函数有this指针,而静态成员
函数没有this指针。静态成员函数可以直接本类中的静态成员函数,因为静态数据成
员同样是属于类的,可以直接访问。一般而言,静态成员函数不访问类中的非静态成
员。
例如:
cout<<"一只小猫的重量是:<<weight<<"千克"<<endl;
//不合法,weight是非静态数据成员
cout<<"一只小猫的总重量是:<<total_weight<<"千克"<<endl;
//合法,total_weight是静态数据成员

若确实需要访问非静态数据成员,静态成员函数只能通过对象名(或对象指针、对象引用)
访问该对象的非静态成员。如把display函数定义为静态成员函数时,可将对象的引用作为
函数参数,将它定义为:
static void display(Small_cat &w)
{
        cout<<"这只小猫的重量是:"<<w.weight<<"千克"<<endl;
}

下面的例子给出了静态成员函数访问非静态数据成员的方法。

例 3.32  静态成员函数访问非静态数据成员。
*/
#include<iostream>
using namespace std;
class Small_cat
{
public:
Small_cat(double w); //声明构造函数
static void display(Small_cat &); //声明静态成员函数
static void total_disp(); //声明静态成员函数
private:
double weight; //普通数据成员,表示一只小猫的重量
static double total_weight; //静态数据成员,用来统计小猫的重量
static double total_number; //静态数据成员,用来统计小猫的数量
};
Small_cat::Small_cat(double w) //定义构造函数
{
weight = w;
total_weight += w; //累加小猫的重量
total_number ++; //累加小猫的数量
}
void Small_cat::display(Small_cat &w) //定义静态成员函数,将对象的引用作为参数,
{ //显示每只小猫的重量
cout<<"这只小猫的重量是:"<<w.weight<<"千克"<<endl;
}
void Small_cat::total_disp() //定义静态成员函数,输出小猫的总数量、总重量
{
cout<<total_number<<"只小猫的重量是:";
cout<<total_weight<<"千克"<<endl;
cout<<endl;
}
double Small_cat::total_weight=; //静态数据成员初始化
double Small_cat::total_number=; //静态数据成员初始化
int main()
{
Small_cat::total_disp(); //在建立对象之前,调用静态成员函数,显示小猫的总数量、总重量 Small_cat w1(0.4),w2(0.5),w3(0.6);
Small_cat::display(w1); //调用静态成员函数,显示第一只小猫的重量
Small_cat::display(w2); //调用静态成员函数,显示第二只小猫的重量
Small_cat::display(w3); //调用静态成员函数,显示第三只小猫的重量 Small_cat::total_disp(); // 在建立对象之后,调用静态成员函数,显示小猫的总数量、总重量 return ;
}

 

C++:静态成员的更多相关文章

  1. JavaScript中的静态成员

    静态:共享 一.公有静态成员(作为函数的属性即可): var Gadget = function(price) { this.price = price; } Gadget.isShiny = fun ...

  2. 面向对象课后深入学习(C++ 类的静态成员详细讲解)

    今天在刚申请了博客,一下午都在写那个随笔,所以说好的来看c++的也放在了最后,下星期就考试了,这个类的静态成员是我不是很懂的,在网上 看到一片很详细的博客考下来回去慢慢看. 在C++中,静态成员是属于 ...

  3. C++类的静态成员详解

    类的静态成员分为静态数据成员和静态成员函数 静态数据成员 假如我们要设计一个战争游戏,游戏中有许多的兵种.游戏的过程中,每隔一段时间每个兵种都会产生,同时由于战争的消耗,每个兵种士兵的数量又会减少.为 ...

  4. Java中,包的概念、常量、静态成员、继承

    新建包:左上角-新建-包 命名规则(通常从大到小,方便整合不容易冲突)  例如:com.itnba.maya.test package必须在最顶行,之前不能再有其他代码 使用包: 快捷方式:使用包中的 ...

  5. C++ - 静态成员函数

    c++中静态成员函数属于整个类, 而不是某个对象,因此不需要创建对象就可以访问 1.出现在类体外的函数定义不能指定关键字static:2.静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访 ...

  6. c++ 类静态成员、非静态成员初始化

    1.静态成员初始化(不能在构造函数或初始化列表中初始化) 1.1 所有静态成员都可以在类定义之外初始化(通用),如下所示 class test { public: static int a; }; ; ...

  7. C#基础——静态成员,static关键字

    当声明一个类成员为静态时,意味着无论创建多少个类的对象,只会有一个该静态成员的副本. 关键字static意味着只有一个该成员的实例.静态变量用于定义常量,因为它们的值可以通过直接调用类而不需要创建类的 ...

  8. C++ 中静态成员函数访问非静态成员变量的方法

    最近在 VS2010 里开发出厂烧写工具,遇到一个问题: 我创建了一个线程,在这个线程里要访问非静态成员,而这个线程函数是静态的.最后找到的办法是用对象指针来做. sourcecode: #test. ...

  9. 缓存篇(Cache)~第一回 使用static静态成员实现服务器端缓存(导航面包屑)

    返回目录 今天写缓存篇的第一篇文章,在写完目录后,得到了一些朋友的关注,这给我之后的写作带来了无穷的力量,在这里,感谢那几位伙伴,哈哈! 书归正传,今天我带来一个Static静态成员的缓存,其实它也不 ...

  10. spring注入静态成员变量提示invalid setter method

    果然还是不够细心啊,被坑一晚上.. 一个极其简单的小程序,但是需要通过xml文件配置注入一个值,唯一的特别是要注入的属性是类中的静态成员变量.. 如下,然后自动生成get和set方法..坑就从此开始了 ...

随机推荐

  1. linux文件的通用操作方法学习

    2014-07-29 23:36:10 在linux下用文件描述符来表示设备文件和普通文件.文件描述符是一个整型的数据,所有对文件的操作都通过文件描述符实现. 文件描述符示文件系统中连接用户空间和内核 ...

  2. Python脚本控制的WebDriver 常用操作 <十七> 获取测试对象的属性及内容

    测试用例场景 获取测试对象的内容是前端自动化测试里一定会使用到的技术.比如我们要判断页面上是否显示了一个提示,那么我们就需要找到这个提示对象,然后获取其中的文字,再跟我们的预期进行比较.在webdri ...

  3. XAML 概述二

    通过上一节我们已经对XAML有了一定的了解,这一节我们来系统的学习一下XAML. 一. 简单属性与类型转换器,属性元素: 我们已经知道 XAML是一种声明性的语言,并且XAML解析器会为每个标签创建一 ...

  4. 使用文件监控对象FileSystemWatcher实现数据同步

    最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容.首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过1S,而且每次获取到文本内容都要去分发给WEB服务 ...

  5. MySQL主从修复

    MySQL主从故障修复 测试库:192.168.1.2 主192.168.1.3 从 192.168.1.4 主 4又是2的从库192.168.1.5 从 有人修改了192.168.1.2和192.1 ...

  6. ES5中的有9个Array方法

    Array.prototype.indexOf Array.prototype.lastIndexOf Array.prototype.every Array.prototype.some Array ...

  7. uImage、zImage、bzImage、vlinzx区别

    在网络中,不少服务器采用的是Linux系统.为了进一步提高服务器的性能,可能需要根 据特定的硬件及需求重新编译Linux内核.编译Linux 内核,需要根据规定的步骤进行,编译内核过程中涉及到几个重要 ...

  8. CSS3实战之新增的选择器

    用的比较少 看到知道怎么回事就ok http://www.w3.org/TR/css3-selectors/#selectors http://www.cnblogs.com/jscode/archi ...

  9. SQL SERVER 强制排序规则查询

    有时会需要在2个DB之间的数据做比较, 但因为一些原因, 数据库的默认排序规则是不一样的, 例如 SELECT A.Col1, B.Col1, A.* FROM DB1.dbo.A LEFT JOIN ...

  10. 20145120 《Java程序设计》第2周学习总结

    20145120 <Java程序设计>第2周学习总结 教材学习内容总结 因为前面有学习过C语言以及汇编语言,类型.运算符.流程控制等很多都是之前接触过的,因此在学习第三章的时候感觉并非十分 ...