主要讲解了静态成员的本质以及静态成员和普通成员的差别,通过对象模型的基本知识体现了静态成员函数和普通函数的差别。
类的静态成员
普通成员变量
普通成员变量受到public和private两个关键字的限制,可以通过类的对象名访问具有public的普通成员变量, 普通的成员变量不能够在类的对象之间共享。静态成员变量
1.在C++中可以定义静态成员变量和静态成员函数, 静态成员属于整个类所有,不需要任何依赖对象。 可以通过类名直接访问public静态成员,可以通过对象名访问public静态成员。 静态成员函数可以直接访问静态成员变量。 2. 普通成员变量依附于具体的对象存在,对象被销毁普通的成员变量就被销毁。在某一个对象诞生的时候静态成员变量不会被创建,同样某一个类被销毁静态成员变量也不会被销毁。它随着类的存在而存在,类是在程序开始运行的时候就存在,所以静态成员变量是随着程序的运行而存在的。 3.静态成员变量不依附于对象的存在而存在,所以 静态成员的空间分配需要在类的外部,也就是在 全局数据区对静态成员变量进行内存的分配。 如果静态成员变量没有被赋予初值,那么静态成员变量和普通的静态变量一样 默认的初始值为0。 4. 静态成员变量在类的内部进行声明,在类的外部进行定义并分配空间。 5.语法规则:在定义时直接通过static关键字进行修饰。语法规则:Type Class Name ::VarName,同时 在类外定义静态成员需要在类的初始化之后,否则编译器无法找到属于这个类的静态成员。静态成员函数
1. 静态成员函数是属于类所有的,并不是依附于某一个对象而存在,调用静态成员函数直接通过类名调用即可。 2. 静态成员函数可以通过类的对象来进行调用。 基本例程如下所示:#include//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类似于命名空间,这里的 静态成员变量,只是这个类的范围的命名空间的全局变量。同样,类的静态成员函数就是这个类的命名空间的全局函数。
类的静态成员的应用
类的静态成员依赖于类而存在,所以可以通过静态成员变量来统计程序中正在运行的类。#includeclass 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/*两种方式在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将当前成员函数的地址提供出来。 例程如下:#includeclass A