1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > c++ ——静态成员变量和静态成员函数

c++ ——静态成员变量和静态成员函数

时间:2020-01-07 06:48:05

相关推荐

c++ ——静态成员变量和静态成员函数

前言

c++ 静态成员变量用static 关键字来声明,是整个类的数据成员,其存储不占用某个具体对象的空间,其存储在静态存储区

c++ 静态成员函数用static 关键字来声明,用于处理静态成员变量,可以用类名来调用,也可以用对象名来调用。

使用静态成员变量的目的:静态成员变量是整个类的数据成员,使用静态成员变量可以实现多个对象共享数据

测试1:

#include <iostream>using namespace std;class Point{public:Point(int xx,int yy):x(xx),y(yy){count++;}Point():Point(0,0){}Point(const Point &p);~Point(){count--;}void show(){cout<<x<<" "<<y<<endl;}static void showcount(); //用static来声明静态成员函数private:int x,y;static int count; //用static来声明静态成员变量};int Point::count = 0; //静态成员变量的定义,定义时前面不可以再有static, 且它必须要在类外面来初始化,不能在类内部初始化。静态成员变量在初始化时分配内存。void Point::showcount() { //静态成员函数的定义,前面不可以再有static,可以在类内部定义,也可以在类外定义。此例为在类外面进行定义。cout<<"count="<<count<<endl;}Point::Point(const Point &p){ //复制构造函数x = p.x;y = p.y;count++;}Point fun(Point m){ return m;}int main(){Point::showcount(); //用类名::函数名来调用静态成员函数Point a(1,2);a.show();a.showcount();//也可用 对象名.函数名 来调用静态成员函数Point b(a);b.show();b.showcount();Point c;c.show();c.showcount();Point d = fun(c);d.show();d.showcount();return 0;}

运行结果:

$ ./a.out

count=0

1 2

count=1

1 2

count=2

0 0

count=3

0 0

count=4

如图,对象a占用8个字节(成员x,y的空间,count不在里面),对象a是局部对象,存放在栈上0x7fffffffdde0的位置处。

count存放在静态存储区的 0x555555756134,不存储在对象中。count属于整个类,不属于某一个具体的对象。

静态成员函数也是一样,属于整个类,不属于某一个对象,所以静态成员函数可以用类名来调用,比如:Point::showcount() 。

static 成员变量必须在类声明的外部初始化,具体形式为:

type class::name = value;

如本例:int Point::count = 0;

静态成员变量在初始化时不能再加 static,但必须要有数据类型。

static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。没有在类外初始化的 static 成员变量不能使用,因为没分配空间。

测试2:

#include <iostream>#include <cmath>using namespace std;class Point{public:Point(int xx,int yy):x(xx),y(yy){count++;}Point():Point(0,0){}Point(const Point &p);~Point(){count--;}void show(){cout<<x<<" "<<y<<endl;}static void showcount();public:static int count; //此例为public属性private:int x,y;};int Point::count = 0;void Point::showcount() {cout<<"count="<<count<<endl;}Point::Point(const Point &p){x = p.x;y = p.y;count++;}int main(){Point::showcount();Point a(1,2);cout<<a.count<<endl; //通过对象a来访问静态成员变量。若count不是public属性,不能用对象来访问,编译时就会报错Point::showcount();Point b(3,4);Point::showcount();return 0;}

用GDB来查看静态成员变量的存储:

可以看到,当b中count变为2,a中count也变为2,即a和b中的count是共享的。查看a.count和b.count的地址,可以发现是同一个地址,即是同一个存储空间。且这个存储空间是全局存储区(静态存储区),不在对象a和对象b的栈(stack)存储区。

此例中count是public,修改为protected和private,编译报错。

protected:static int count;

private:static int count;

如上图,也就是说,想通过对象来访问静态成员变量,静态成员变量只能是public属性。这一点和对象去访问普通的成员变量一样。类外面,对象只能访问public成员变量,不能访问protected和private的成员变量。

测试3:

void Point::showcount() {cout<<"count="<<count<<endl;cout<<x<<endl; //新增,尝试在静态成员函数中去访问普通的成员变量,编译报错。}

也即是说,在静态成员函数中,不能去访问普通的成员变量。原因是没有this指针,不知道普通成员变量x放在哪里。

原因分析:

编译器在编译一个普通成员函数时,会隐式地增加一个形参 this,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象之后通过对象来调用,因为它需要当前对象的地址。也即是有了对象,才有对象的this指针,没有对象,就无法调用普通成员函数。由于类没有this指针,所以不能用类名去调用普通成员函数,只能用实际的对象去调用普通成员函数

而静态成员函数可以通过类来直接调用,编译器不会为它增加形参 this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。因为静态成员函数要访问的是静态成员变量(存储在全局存储区,和this指针没毛关系)。

由于静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,所以静态成员函数不能访问普通成员变量,只能访问静态成员变量

总结:

一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。注意,是共享,共享,共享,也即是只会占同一份静态存储空间。static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。根本原因是静态成员变量和对象的存储空间不同,是在不同的时期去分配的。静态成员变量必须初始化,而且只能在类体外进行。例如:

int Point::count = 0;

初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为 0

全局数据区的变量都有默认的初始值 0,而**动态数据区(堆区、栈区)**变量的默认值是不确定的,一般认为是垃圾值。静态成员变量既可以通过对象名访问,也可以通过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。

当在类外面通过对象名访问时,静态成员变量属性必须是public,对于不同的对象时,访问的是同一份内存(本质是共享)。静态成员函数在声明时要加 static,在定义时不能加 static。静态成员函数只能访问静态成员变量,去访问普通成员变量,编译就报错。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。