第11课 - 类的静态成员
一.类的普通成员的回顾
1.1 通过对象名能够访问public成员变量
1.2 每个对象都可以有只属于自己的成员变量
1.3 成员对象不能在对象之间共享
1.4 新的需求:
a.统计类在程序运行期间有多少个对象同时存在
b.保证程序的安全性(不能使用全局变量),并随时可以获取对象数目
如果使用普通的成员变量,对象存在那么成员变量存在
对象销毁的时候成员变量也会被销毁,因此成员变量没有能力来统计对象的个数的。
二.类的静态成员(属于类)
2.1 类的静态成员特点
2.1.1 在C++中可以定义静态成员变量和静态成员函数
2.1.2 静态成员属于整个类所有,不需要依赖任何对象
2.1.3 可以通过类名直接访问public静态成员
2.1.4 可以通过对象名访问public静态成员
2.1.5 静态成员函数可以直接访问静态成员变量
2.2 静态成员变量的定义
2.2.1 在定义是直接通过static关键字修饰
2.2.2 静态成员变量不依赖于任何对象,需要在类外单独分配空间,即存在于全局数据区
2.2.3 语法规则: Type ClassName::VarName;
2.3 静态函数的定义
2.3.1 在定义时直接通过static关键字修饰
2.3.2 其余部分与普通成员函数定义相同
Source Example 2:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test{
private:
static int i;
public:
static int getI(void)
{
return i;
}
static void setI(int a)
{
i = a;
}
void print()
{
printf ("i = %d\n", i);
}
};
/* 必须为i分配空间,在全局数据区 */
int Test :: i = 0;
int main(int argc, char** argv) {
/* 下面这句会出错,因为即使i是静态变量也会被private限制 */
//Test::i = 5;
/* 静态函数不依赖于对象,直接根据类就可以调用 */
Test::setI(5);
int x = Test::getI();
printf ("x = %d\n", x);
/* 执行下面这句会出错,因为print不是静态函数,需要依赖于对象才可以调用 */
//Test::print();
return 0;
}
注意:静态成员变量属于类,因此也属于对象,可以使用对象修改静态成员变量的值。
2.4 从命名空间的角度看
2.4.1 类的静态成员只是类这个命名空间中的全局变量和全局函数
2.4.2 不同之处是,类可以对静态成员进行访问权限的限制,而命名空间不行
2.5 从面向对象的角度看
2.5.1 类的静态成员属于类概念本身
2.5.2 类的所有对象共享相同的静态成员
三.静态成员的应用(统计某个类的对象数目)
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test{
private:
static int iCount;
public:
static int GetCount()
{
return iCount;
}
Test()
{
iCount++;
}
~Test()
{
iCount--;
}
};
/* 如果没有赋初始值,默认值是0,因为放在全局数据区 */
int Test::iCount = 0;
void run()
{
Test ta[100];
/* 输出结果为100 */
printf ("Number of object = %d\n", Test :: GetCount());
}
int main(int argc, char** argv) {
run();
/* 输出结果为0 */
printf ("Number of object = %d\n", Test :: GetCount());
return 0;
}
四.静态成员函数和普通成员函数的区别
4.1 C++类对象中的成员变量和成员函数时分开存储的
4.1.1 成员变量
普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节对齐方式
静态成员变量:存储于全局数据区中
4.1.2 成员函数
存储于代码段中
程序依然由数据段(计算机数据)和代码段(可执行代码)构成
Source Example 4.1:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/* struct与class的区别只有访问权限不同,class默认是private,struct默认是public */
struct C1 {
int i;
int j;
short k;
short l;
};
class C2 {
int i;
int j;
short k;
short l;
};
class C3 {
int i;
int j;
short k;
short l;
/* 静态成员函数,不占用class的空间,存储在全局数据区 */
static int x;
public:
/* 函数存储与代码段中 */
C3()
{
}
void print()
{
}
};
/* 为静态x成员分配空间 */
int C3::x = 0;
int main(int argc, char** argv) {
C1 c1;
C2 c2;
C3 c3;
/* 输出结果为:
sizeof (C1) = 12
sizeof (C2) = 12
sizeof (C3) = 12
*/
printf ("sizeof (C1) = %d\n",sizeof (c1));
printf ("sizeof (C2) = %d\n",sizeof (c2));
printf ("sizeof (C3) = %d\n",sizeof (c3)) ;
return 0;
}
/* C++编译器将程序转换为面相对象内部处理 */
Source Example 4.2 :
/* C++代码 */ /* 编译器内部处理方式 */
class Test struct class
{ {
int i;
private: }
int i;
public: /* 一个pThis指针指向当前创建的对象 */
Test(int x) void Test_initialize(Test* pThis, int x)
{ {
i = x; pThis->i = x;
} }
int getI() int Test_getI(Test* pThis)
{ {
return i; return pThis->i;
} }
static void Print() void Test_Print()
{ {
printf ("This is a class Test!\n"); printf("This is a class Test!\n");
} }
}
int main() int main()
{ {
Test a(10); Test a;
Test_initialize(&a, 10);
a.getI(); Test_getI(&a);
/* 该函数是静态函数,不属于对象,因此不需要pThis指针 */
Test::Print(); Test_Print();
return 0; return 0;
} }
因此得出结论(静态成员函数与普通成员函数的区别)
a.静态成员函数不包含指向具体对象的指针
b.普通成员函数包含一个指向具体对象的指针
C++中类的普通成员函数都隐士包含一个指向当前对象的this指针。
再次验证this指针:
/* 静态成员与非静态成员区别 */
Source Example 4.3:
#include <iostream>
class Test {
private:
int i;
int j;
int k;
/* 静态成员函数,不占用class的空间,存储在全局数据区 */
static int x;
public:
Test(int i, int j, int k)
{
/* 如下方式赋值会造成作用域重叠,都是用参数的i,j,k,因此类中的i,j,k为随机数
* i = i;
* j = j;
* k = k;
* this指针指向当前对象
*/
this->i = i;
this->j = j;
this->k = k;
}
void print()
{
/* t1的this指针地址为22fe50与&t1相同,说明了this指针指向了当前对象 */
printf ("this pointer address = %08x\n", this);
/* t1,t2的&x地址相同,证明了静态成员存储与全局数据区中 */
printf ("&x = %08x, x= %d\n", &x, x);
printf ("&i = %08x, i = %d\n", &i, i);
printf ("&j = %08x, j = %d\n", &j, j);
printf ("&k = %08x, k = %d\n", &k, k);
}
/* 加上如下代码编译出错,因为静态成员函数没有this指针,从上一个例子中C++内部处理方式也可以看出。
* static void Print()
* {
* printf ("this pointer address = %08x\n", this);
* }
*/
};
/* 为静态x成员分配空间 */
int Test::x = 0;
int main(int argc, char** argv) {
Test t1(1,2,3);
Test t2(4,5,6);
printf ("&t1 = %08x\n", &t1);
t1.print();
printf ("&t2 = %08x\n", &t2);
t2.print();
return 0;
}
输出结果如下: