C++:静态成员

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

 例3.28  静态数据成员的引例 

#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)+1];//为学生姓名动态分配一个空间,并让name指向数组的首地址
  strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制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<<"姓名:"<<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("李明","1101",90.0);
 stu1.show();
 stu1.show_count_sum_ave();
 cout<<"------------------------"<<endl;

 Student stu2("王勇","1102",92.5);
 stu2.show();
 stu2.show_count_sum_ave();

 return 0;
}
/*
  运行结果发现:学生人数、总成绩、平均成绩都是错误的。

  其原因:一个学生对象的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)+1];//为学生姓名动态分配一个空间,并让name指向数组的首地址
  strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制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<<"姓名:"<<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=0;  //对静态数据成员count进行初始化
float Student::sum=0;  //对静态数据成员sum进行初始化
float Student::ave=0;  //对静态数据成员ave进行初始化
int main()
{
 Student stu1("李明","1101",90.0);
 stu1.show();
 stu1.show_count_sum_ave();
 cout<<"------------------------"<<endl;

 Student stu2("王勇","1102",92.5);
 stu2.show();
 stu2.show_count_sum_ave();

 return 0;
}

说明:
(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=0;  //对静态数据成员count进行初始化
float Student::sum=0;  //对静态数据成员sum进行初始化
float Student::ave=0;  //对静态数据成员ave进行初始化
int main()
{
 Student stu1("李明","1101",90.0);
 stu1.show();
 stu1.show_count_sum_ave();
 cout<<"------------------------"<<endl;

 Student stu2("王勇","1102",92.5);
 stu2.show();
 stu2.show_count_sum_ave();

 return 0;
}

例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)+1];//为学生姓名动态分配一个空间,并让name指向数组的首地址
  strcpy(name,name1);//首先name把name1指向的首地址复制过来,然后依次复制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<<"姓名:"<<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=0;  //对静态数据成员count进行初始化
float Student::sum=0;  //对静态数据成员sum进行初始化
float Student::ave=0;  //对静态数据成员ave进行初始化
int main()
{
 Student stu1("李明","1101",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("王勇","1102",92.5),*p2;
 p2 = &stu2;
 //p2->show();
 //p2->show_count_sum_ave();
 (*p2).show();
 (*p2).show_count_sum_ave();

 return 0;
}

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

#include<iostream>
using namespace std;
class Myclass{
  public:
    static int i;
    int get()
    {
      return i;
    }
};
int Myclass::i=0;
int main()
{
  Myclass::i=200;  //公有静态数据成员可通过对象进行访问
  Myclass obj1,obj2;
  cout<<"obj1.i="<<obj1.get()<<endl;
  cout<<"obj2.i="<<obj2.get()<<endl;

  obj1.i=300;//公有静态数据成员通过对象进行访问并进行重赋值

  cout<<"obj1.i="<<obj1.get()<<endl;
  cout<<"obj2.i="<<obj2.get()<<endl;

  return 0;
}
/*

运行结果为:  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=0;     //对私有的静态数据成员进行初始化
 double Small_cat::total_number=0;     //对私有的静态数据成员进行初始化
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  0;
} 

对静态成员函数的使在作几点说明:
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=0;             //静态数据成员初始化
double Small_cat::total_number=0;             //静态数据成员初始化
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 0;
}

 

时间: 2024-10-13 00:23:05

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

类静态成员(难点)

一.类静态数据成员 静态成员的提出是为了解决数据共享的问题.实现共享有许多方法,如:设置全局性的变量或对象是一种方法.但是,全局变量或对象是有局限性的.这里主要讨论用类的静态成员来实现对象间的数据的共享. 静态数据成员的使用方法和注意事项如下: 1.静态数据成员在定义或说明时前面加关键字static. 2.静态成员初始化与一般数据成员初始化不同.静态数据成员初始化的格式如下: <数据类型><类名>::<静态数据成员名>=<值> 3.静态数据成员是静态存储的,

C++静态成员变量需注意的问题

1.在类的内部仅仅进行声明 为什么? 因为如果这样的话,每构造一个对象就要进行一次初始化,而这样就不能达到类共享的目的. 2.在类的外部要进行初始化 为什么? 因为在类的仅仅进行了声明(编译器会这样认为),没有分配存储空间,在类外进行初始化话,是为了分配存储空间. 3.初始化时不加static 示例 #include "stdafx.h" #include <iostream> using namespace std; class A { public: static in

C++程序设计方法3:类中的静态成员

在类型前面加static修饰的数据成员,是隶属于类的,成为类的静态数据成员,也称为"类的变量" 静态数据成员被该类的所有对象共享(即所有对象中的这个数据域实际上处于同一个内存位置) 静态数据要在实现文件中赋初值,格式为: Type ClassName::static_var = Value; 返回值类型前面加static修饰的成员函数,称为静态成员函数,它们不能调用非静态成员函数: 类的静态成员(数据,函数)既可以通过对象来访问,也可以通过类名字类访问: #include <io

成员函数指针和指向静态成员函数的指针

#include <iostream> using namespace std; class Student{ public:     Student(const string& name):m_name(name){}     void who(void){         cout << m_name << endl;     }     string m_name;     static int s_add(int a,int b){         re

C++中类的静态成员初始化

静态成员的初始化: 与全局对象一样对于静态数据成员在程序中也只能提供一个定义,这意味着静态数据成员的初始化不应该被放在头文件中而应该放在含有类的非inline函数定义的文件中. 转自:http://blog.csdn.net/veryday_code/article/details/7921833 能在类中初始化的成员只有一种,那就是静态常量成员. class A { private: static const int count = 0; // 静态常量成员可以在类内初始化 }; 结论: 静态

c++静态成员与静态函数

1 静态成员的定义 1 静态变量 c++在类里面进行的仅是引用性声明,不会为之分配内存,要求必须单独对静态数据成员进行定义性的声明.形式为: 类型 类名::静态数据成员名: 此时的定义需要再加关键字static,并且可以在定义时初始化. c++要求类中成员变量不可以直接初始化,可以采用定义函数方法时后挂变量方式初始化. 这与Java不同. 2 静态函数 定义方式与静态变量同.函数的定义可以在类内也可以在类外. class A { public: A(int y) { a=y; cout<<a+

静态成员函数不能采用const修饰的原因

静态成员函数不能用const修饰 ,也不能存取nonstatic数据 C++中静态成员函数不能用const修饰的原因: static在c++中的第五种含义:用static修饰不访问非静态数据成员的类成员函数.这意味着一个静态成员函数只能访问它的参数.类的静态数据成员和全局变量. 不能用const的原因:一个静态成员函数访问的值是其参数.静态数据成员和全局变量,而这些数据都不是对象状态的一部分.而对成员函数中使用关键字const是表明:函数不会修改该函数访问的目标对象的数据成员.既然一个静态成员函

C++里的静态成员函数不能用const的原因

From http://blog.csdn.net/freeboy1015/article/details/7634950 static在c++中的第五种含义:用static修饰不访问非静态数据成员的类成员函数.这意味着一个静态成员函数只能访问它的参数.类的静态数据成员和全局变量. 不能用const的原因: 这是C++的规则,const修饰符用于表示函数不能修改成员变量的值,该函数必须是含有this指针的类成员函数,函数调用方式为thiscall,而类中的static函数本质上是全局函数,调用规

C++模板 静态成员 定义(实例化)

问一个问题: 考虑一个模板: template <typename T> class Test{ public: static std::string info; }; 对于下面若干种定义方式.哪些是对的(通过编译)? template <> string Test<int>::info("123"); template <typename T> string Test<T>::info("123"); t

回调函数中调用类中的非静态成员变量或非静态成员函数

有关这方面的问题,首先说一点: 回调函数必须是静态成员函数或者全局函数来实现回调函数,大概原因是普通的C++成员函数都隐含了一个函数参数,即this指针,C++通过传递this指针给成员函数从而实现函数可以访问类的特定对象的数据成员.由于this指针的原因,使得一个普通成员函数作为回调函数时就会因为隐含的this指针问题使得函数参数个数不匹配,从而导致回调函数编译失败. 基于上面的理论,如何在类中封装回调函数呢? 回调函数只能是全局函数或者静态成员函数,但是由于全局函数会破坏封装性,所以只能用静