归纳编程学习的感悟,
记录奋斗路上的点滴,
希望能帮到一样刻苦的你!
如有不足欢迎指正!
共同学习交流!
🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言📝
信念,你拿它没办法,但没有他你什么也做不成!
一起加油!
目录
一、前言:
二、静态数据成员:
⭐例:具有静态数据成员的 Student 类。
🔑说明:
三、静态成员函数:
⭐例:类中静态数据成员和静态函数成员示例。
⚡思考:
四、静态成员的访问:
⭐例:类中静态成员函数通过对象访问非静态成员示例。
五、总结:
六、共勉:
一、前言:
我们知道在一个函数内部定义的静态局部变量可以在每次函数调用间实现数据共享。这种共享仅限于这个函数调用之间,因为在函数外部是无法访问到函数内部的局部变量的。我们也可以将函数和函数要访问的数据封装成一个类,这样类中的数据成员可以被类中任何一个函数访问。一方面在类内部的函数之间实现了数据的共享,另一方面这种共享是受限制的,通过设定一定的访问权限后,可以把共享仅限定在类的范围之内。
数据的共享包括很多、有时候类的对象与对象之间也需要共享数据。静态成员是解决同一个类的不同对象之间数据和函数的共享问题。例如,学生类的声明如下:
class Student{
protected:
int ID;
char*name;
//....其他数据成员与成员函数略};
假设设计了一个学生管理系统,系统中随时定义新的学生对象,如果要统计系统中所有学生对象的数目,这个数据应该怎么存放呢?当然也可以在类外设计一个全局变量来存放总数,但这种做法不能实现数据的隐藏。如果在类的内部增加一个数据成员用于存放总数,那么类中的数据成员在类的每个对象中都有一个副本,不仅会造成数据冗余,而且每个对象都分别维护一个“总数”,很容易造成各对象数据的不一致。这个“总数”是为类的所有对象所共同拥有的,应该声明为类的静态数据成员。
二、静态数据成员:
在类中声明静态数据成员的格式如下:
class 类名
{
static <静态数据成员的声明>;
}
类中声明的静态数据成员仅仅是引用性声明,必须在命名空间作用域的某个地方使用类名限定定义性声明,这时也可以进行初始化。与类的一般数据成员不同,静态数据成员需要在类定义之外再进行定义,因为需要以这种方式专门为它们分配空间。非静态数据成员的数据空间是与它们所属对象的空间同时分配的。一般在类的实现部分完成静态数据成员的初始化。静态成员定义及初始化格式如下:
类名::静态数据成员标识符=初始值;
静态成员是类的所有对象共享的成员,而不是某个对象本身的成员,它在对象中不占存储空间。在使用时,可以通过对象引用类的静态成员,也可以不定义对象,通过类直接引用静态成员。
⭐例:具有静态数据成员的 Student 类。
#include<iostream>
#include<cstring>
using namespace std;
class Student{//Student类定义
protected:
int ID;
char *name;//name为需要动态申请的空间
char sex;
int age;
static int count;//静态数据成员的声明,用来记录学生的个数
public://外部接口
Student(int pID,char *pname,char psex,int page);//构造函数
~Student();//析构函数
void print();
void Show_count(){//输出静态数据成员
cout<<"Object count:"<<count<<endl;
}
};
Student::Student(int pID,char *pname,char psex,int page){
ID=pID;
name=new char[strlen(pname)+1];//为name动态申请空间
strcpy(name,pname);//将值放入name所指向的内存空间
sex=psex;
age=page;
count++;//在构造函数中对count++,所有对象成员共同维护一个count
}
Student::~Student(){
count--;//在析构函数中对count进行减减操作
delete []name;
}
void Student::print(){
cout<<"ID:"<<ID<<"\nName:"<<name<<"\nSex:"<<sex<<"\nAge:"<<age<<endl;
}
int Student::count=0;
int main(){
Student std1(20230011,"李华",'F',18);//定义对象std1,其构造函数会使count++
std1.print();
std1.Show_count();//输出对象的个数
Student std2(20230012,"张三",'M',19);//定义对象std2,其构造函数会使count++
std2.print();
std2.Show_count();//输出对象的个数
return 0;
}
🔑说明:
类Student 中的静态数据成员 count,用来统计 Student 类的对象个数,每定义一个新对象,count 的值就相应加 1,静态成员 count 的定义和初始化必须在类外进行,初始化时引用的方式要注意两点: (1).必须用类名来引用;(2)虽然静态数据成员在类中声明的是私有的,在这里却可以直接初始化。除了定义初始化的时候,在其他地方,例如,在主函数中就不允许直接访问了。count 的值是在类的构造函数中计算的,std1 对象生成时,调用构造函数;std2 对象生成时,调用构造函数。两次调用构造函数访问的均是同一个静态成员 count。通过对象 std1 和对象 std2 分别调用 Show_count 函数,输出的也是同一个 count在不同时刻的数值。这样,就实现了 std1 和 std2 两个对象之间的数据共享。
三、静态成员函数:
函数 Show_count 是专门用来输出静态成员 count 的。count 是类中的私有成员如果需要查看 count 的值,需要调用类的公有接口函数 showCount。在所有对象声明之前,系中对象的个数为 0,可否通过 Show_Count 将这个值输出呢?由于此时系统中还没有对象,无法通过对象来调用 Show_Count,由于 count 是整个类共有的,不属于某一个对象。因此,我们希望对count 的访问也可以不通过对象,而直接通过类名来访问。在主函数中增加了类直接调Show_count语句,如下所示:
int main(){
Student::Show_count();
Student std1(20230011,"李华",'F',18);//定义对象std1,其构造函数会使count++
std1.print();
std1.Show_count();//输出对象的个数
Student std2(20230012,"张三",'M',19);//定义对象std2,其构造函数会使count++
std2.print();
std2.Show_count();//输出对象的个数
return 0;
}
编译后“Student::showCount0:”语句出错,提示对普通函数 Show_count 的调用必须通过对象名。
可以将函数 Show_count 也声明为静态的,同静态数据成员一样,静态成员函数也属于整个类,由同一类的所有对象共同拥有,为这些对象共享。静态成员函数可以直接由类调用。不需要通过类定义对象后再调用。
⭐例:类中静态数据成员和静态函数成员示例。
#include<iostream>
#include<cstring>
using namespace std;
class Student{//Student类定义
protected:
int ID;
char *name;//name为需要动态申请的空间
char sex;
int age;
static int count;//静态数据成员的声明,用来记录学生的个数
public://外部接口
Student(int pID,char *pname,char psex,int page);//构造函数
~Student();//析构函数
void print();
static void Show_count(){//静态成员函数输出静态数据成员
cout<<"Object count:"<<count<<endl;
}
};
Student::Student(int pID,char *pname,char psex,int page){
ID=pID;
name=new char[strlen(pname)+1];//为name动态申请空间
strcpy(name,pname);//将值放入name所指向的内存空间
sex=psex;
age=page;
count++;//在构造函数中对count++,所有对象成员共同维护一个count
}
Student::~Student(){
count--;//在析构函数中对count进行减减操作
delete []name;
}
void Student::print(){
cout<<"ID:"<<ID<<"\nName:"<<name<<"\nSex:"<<sex<<"\nAge:"<<age<<endl;
}
int Student::count=0;
int main(){
Student::Show_count();
Student std1(20230011,"李华",'F',18);//定义对象std1,其构造函数会使count++
std1.print();
std1.Show_count();//输出对象的个数
Student std2(20230012,"张三",'M',19);//定义对象std2,其构造函数会使count++
std2.print();
std2.Show_count();//输出对象的个数
return 0;
}
⚡思考:
可以在静态成员函数 Show_count 中访问非静态成员x、y吗?
四、静态成员的访问:
类中非静态的成员只能通过对象名来调用,而静态成员包括静态数据成员和静态成员函数,可以在类外通过类名和对象名来调用。但要习惯使用类名调用静态成员,因为即使是通过对象名调用静态成员,实质上也是通过对象的类型信息确定调用类的静态成员,与具体对象没有任何关系。
在一般情况下,类中静态成员函数主要用于访问同一个类中的静态数据成员,而不能访问类
中的非静态数据成员。因为静态成员函数实质上并不是由某个具体对象来调用的,所以不能隐含
地通过调用对象访问类中的非静态成员。
我们不能在静态成员函数 Show_count 中访问本类的非静态成员x和y。如果一定要在静态成员函数中访问非静态成员,可以显式地通过对象来调用。
⭐例:类中静态成员函数通过对象访问非静态成员示例。
#include<iostream>
#include<cstring>
using namespace std;
class Student{//Student类定义
protected:
int ID;
char *name;//name为需要动态申请的空间
char sex;
int age;
static int count;//静态数据成员的声明,用来记录学生的个数
public://外部接口
Student(int pID,char *pname,char psex,int page);//构造函数
~Student();//析构函数
static void Show_count(Student p){
//静态成员函数访问静态数据成员和非静态数据成员
cout<<"Object count:"<<count<<endl;//静态成员函数直接访问静态信息
cout<<"ID:"<<p.ID<<"\nName:"<<p.name<<"\nSex:"<<p.sex<<"\nAge:"<<p.age<<endl;
//静态成员函数需要通过对象访问非静态信息
}
};
Student::Student(int pID,char *pname,char psex,int page){
ID=pID;
name=new char[strlen(pname)+1];//为name动态申请空间
strcpy(name,pname);//将值放入name所指向的内存空间
sex=psex;
age=page;
count++;//在构造函数中对count++,所有对象成员共同维护一个count
}
Student::~Student(){
delete []name;
}
int Student::count=0;
int main(){
Student std1(20230011,"李华",'F',18);//定义对象std1,其构造函数会使count++
std1.Show_count(std1);//通过静态成员函数访问非静态信息需要通过对象
Student std2(20230012,"张三",'M',19);//定义对象std2,其构造函数会使count++
std2.Show_count(std2);//通过静态成员函数访问非静态信息需要通过对象
return 0;
}
五、总结:
- 静态成员是解决同一个类的不同对象之间数据和函数的共享问题。
- 一般在类的实现部分完成静态数据成员的初始化。
- 静态成员是类的所有对象共享的成员,而不是某个对象本身的成员,它在对象中不占存储空间。
- 静态成员函数可以直接由类调用。不需要通过类定义对象后再调用。
- 静态成员包括静态数据成员和静态成员函数。
- 即使是通过对象名调用静态成员,实质上也是通过对象的类型信息确定调用类的静态成员,与具体对象没有任何关系。
六、共勉:
以上就是我对C++共享和保护——(3)静态成员的理解,希望本篇文章对你有所帮助,也希望可以支持支持博主,后续博主也会定期更新学习记录,记录学习过程中的点点滴滴。如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++共享和保护的理解,请持续关注我哦!!!