C++基础学习笔记----第十一课(类的静态成员、对象模型初步认识)

来源:互联网 发布:php二次开发ecshop 编辑:程序博客网 时间:2024/04/28 00:33

主要讲解了静态成员的本质以及静态成员和普通成员的差别,通过对象模型的基本知识体现了静态成员函数和普通函数的差别。

类的静态成员

普通成员变量

普通成员变量受到public和private两个关键字的限制,可以通过类的对象名访问具有public的普通成员变量,普通的成员变量不能够在类的对象之间共享

静态成员变量

1.在C++中可以定义静态成员变量和静态成员函数,静态成员属于整个类所有,不需要任何依赖对象可以通过类名直接访问public静态成员,可以通过对象名访问public静态成员静态成员函数可以直接访问静态成员变量
2.普通成员变量依附于具体的对象存在,对象被销毁普通的成员变量就被销毁。在某一个对象诞生的时候静态成员变量不会被创建,同样某一个类被销毁静态成员变量也不会被销毁。它随着类的存在而存在,类是在程序开始运行的时候就存在,所以静态成员变量是随着程序的运行而存在的。
3.静态成员变量不依附于对象的存在而存在,所以静态成员的空间分配需要在类的外部,也就是在全局数据区对静态成员变量进行内存的分配如果静态成员变量没有被赋予初值,那么静态成员变量和普通的静态变量一样默认的初始值为0
4.静态成员变量在类的内部进行声明,在类的外部进行定义并分配空间。
5.语法规则:在定义时直接通过static关键字进行修饰。语法规则:Type Class Name ::VarName,同时在类外定义静态成员需要在类的初始化之后,否则编译器无法找到属于这个类的静态成员。

静态成员函数

1.静态成员函数是属于类所有的,并不是依附于某一个对象而存在,调用静态成员函数直接通过类名调用即可。
2.静态成员函数可以通过类的对象来进行调用。
基本例程如下所示:
#include <stdio.h>//int A::ai; 类的静态变量定义在类的前面将会报错class A{private:static int ai;public:static int getai(){return ai;}static int setai(int i){ai = i;return 0;}void print(){printf("ai = %d\n", ai);}};int A::ai = 0;int main(){/*不需要建立类的对象就可以调用类的静态成员函数*/A::setai(9);printf("ai = %d\n",A::getai());/*print函数是类的普通成员函数,需要建立类的对象来完成调用*/A a;a.print();A a1;/*可以通过类的对象来抵用类的静态成员函数*/a1.setai(6);printf("ai = %d\n",a1.getai());//a1.ai = 8; 虽然可以通过类的对象来改变静态成员变量的值,但是这里的静态成员变量仍然受到public和private属性的限制。    return 0;}

C++不同角度上的类的静态成员

命名空间的角度:
通过上面的例程,可发现在类的外部定义类的静态成员变量的代码:
int A::ai = 0;
这里的A::ai类似于命名空间,这里的静态成员变量,只是这个类的范围的命名空间的全局变量。同样,类的静态成员函数就是这个类的命名空间的全局函数。
不同的地方是,类可以对静态成员变量进行访问权限的限制(使用public和private关键字),而命名空间不可以。
面向对象的角度:
类的静态成员属于类的概念本身,类的所有对象共享相同的静态成员。

类的静态成员的应用

类的静态成员依赖于类而存在,所以可以通过静态成员变量来统计程序中正在运行的类。
#include <stdio.h>class A{private:static int ai;public:static int getai(){return ai;}A(){ai++;}~A(){ai--;}};/*如果不给静态成员变量赋初值,那么ai的默认值为0*/int A::ai;void run(){A a[100];/*这里定义了一个100A类的数组,所以通过调用静态成员函数ai再次进行100次自加,打印102*/printf("%d\n",A::getai());/*run()函数在调用结束后100个A类的数组自动被销毁,调用析构函数,ai自减100*/}int main(){A a1;A a2;/*定义两个A类的对象后,ai通过定义的默认构造函数自加两次,这里打印2*/printf("%d\n",A::getai());run();/*run函数调用结束返回,这个时候静态成员变量的值是2*/printf("%d\n",A::getai());    return 0;}

C++对象模型初探

普通成员变量和struct变量的存储

1.C++中的成员变量和成员函数是分开存储的。成员变量分为普通成员变量和静态成员变量,普通的成员变量存储在对象中与struct变量具有相同的内存布局和字节对齐方式。静态成员变量存储在程序的全局数据区。
2.成员函数存储在代码段中,无论是静态成员函数还是普通的成员函数。

例程:
#include <stdio.h>/*两种方式在C++定义类的差别在于:A默认的成员是private,B默认的成员是public*/class A{int i;int j;short a;char b;};struct B{int i;int j;short a;char b;};class C{private:int i;int j;short a;char b;/*静态成员变量占用的全局数据区的内存空间*/static int h;public:/*成员函数占用的代码段的内存空间*/C(){printf("abc\n");}int print(){i = 1;return 0;}};int C::h = 0;int main(){/*根据C语言中的内存对齐,A和B结构体占用的内存空间都为12个字节*/printf ("%d\n",sizeof(A));printf ("%d\n",sizeof(B));/*程序的打印结果和结构体A和B的打印结果相同*/printf ("%d\n",sizeof(B));    return 0;}

C++中的对象模型

面向对象理论到计算机程序的转化基本程序(这里只是一个简单的例子,具体的实现还是C++编译器内部的实现),如下图所示:

静态成员函数和普通成员函数的差别

1.普通成员函数不包含指向具体对象的指针,普通成员函数包含一个指向具体对象的指针
2.C++中类的普通成员函数都隐式包含一个指向当前对象的this指针。
3.静态成员函数没有this指针,普通成员函数有。普通成员函数通过C++默认的关键字this将当前成员函数的地址提供出来。
例程如下:
#include <stdio.h>class A{private:int a;int b;int c;static int d;public:A(int a, int b, int c){/*如果这里这样定义将会造成二义性,程序最后将无法确定怎么进行赋值,所以这里编译报错*//*this->a = a;this->b = b;this->c = c;*//*这里的this是C++中的关键字,这里的this指针指向当前的对象所以this->a是指向这个类的成员变量a*/this->a = a;this->b = b;this->c = c;}void print(){/*打印各个变量的值和变量地址*/printf("a = %d, &a = %p\n",a,&a);printf("b = %d, &b = %p\n",b,&b);printf("c = %d, &c = %p\n",c,&c);/*通过地址打印可以看出d的地址和变量a,b,c的地址并不是连续的,可以进一步证明静态成员变量的内存分配来自全局数据区*/printf ("d = %d, &c = %p\n",d,&d);/*这里打印this指针的地址,也是具体的对象的地址,随着对象的创建而this指针式不同的*/printf("%p\n",this);}};int A::d = 0;int main(){A g  = A(2,3,4);g.print();printf ("&g = %p\n", &g);A g2 = A(7,8,9);g2.print();printf ("&g = %p\n", &g2);    return 0;}


原创粉丝点击