5、类的静态成员
问题: 如何统计对象的个数呢?
(1)普通的成员变量?不行,因为对于普通的成员变量,对象都有各自的成员变量,他们都是相互独立的,所以并不能实现对象个数的统计
(2)全局变量:可以,但是一般来说,我们都是尽量避免全局变量(周期长,占内存,出错的时候, 不易查找),
(3)类的静态成员变量和静态成员函数: YES
静态成员:
(1)静态成员是属于整个类所有的,不依赖于任何对象,依赖于类的存在(所以才可以通过类名直接访问静态成员变量和静态成员函数),对象的创建和销毁都不会影响静态成员
(2)可以通过类名来访问 public 的静态成员(不能通过类名访问普通的成员函数,只有静态成员函数才可以通过类名访问)
(3)可以通过对象名访问public 的静态成员
(4)静态成员不要在类内进行赋值,因为它是被所有该类的对象共享的,一般都是在类外进行初始化
(5)静态成员函数只可以直接访问静态成员变量和静态成员函数,不可以访问非静态成员变量和非静态成员函数(而非静态成员函数则可以访问所有的不论是静态还是非静态,也就是可以访问静态成员变量和静态成员函数,更可以访问非静态成员变量和静态成员函数)
静态成员变量:
其实就是直接在类内部变量声明处加上 static 关键字就可以,静态成员变量不依赖于任何对象,需要在类外单独分配空间;其实就是就存储在全局的数据区(静态存储区域)。
class Test { public: Test(); ~Test(); private: static int b; // 静态成员声明 }; int Test::b = 0; // 在类的外部,进行静态成员变量的初始化
之所以在类的进行静态成员变量的初始化的原因是因为,在类的内部初始化的话,就会被类的全部对象共享,这不是我们要的目的;所以,一般类的静态成员变量是在类的外部进行静态成员变量初始化。
可以理解为:类的静态成员,是在类内命名空间内部的全局变量,也就是说,静态成员变量是类内的全局变量。
静态成员函数:
就是函数名加上 static 关键字
class A { private: static int i; // 静态成员变量,添加 static 关键字 public: static int geti() // 静态成员函数,static 关键字 { return i; } static void seti( int v) { i = v; } }; // 不要在类内进行初始化,因为静态成员变量是所有的对象的共有的, int A::i = 10; // 静态成员变量进行初始化 int main() { A aa; aa.seti(10); // 静态成员变量是private,所以只能被类内的函数访问 printf("i = %d\n", aa.geti()); // 通过对象进行访问 printf("i = %d\n", A::geti()); // 通过类名访问 while (1); }
注意:
静态成员函数可以(只能)直接访问该类内的静态成员变量和静态成员函数(无法访问非静态成员变量和非静态成员函数),但是不能直接引用非静态成员变量和非静态成员函数,会报错的。如果非要进行引用的话,除非通过传参的方式得到对象名,再通过对象的访问达到目的。
实现对象个数的统计:
class A { private: static int count; // 静态成员变量 public: A() // 构造函数 { count++; } ~A() // 析构函数 { count--; } }; int A::count = 0; // 静态成员变量进行初始化
类的对象每次创建,count 就会自加一,对象的销毁的时候,就自减一,所以就完成了对象个数的实现(非静态成员函数可以访问静态成员函数和静态成员变量);
注意:
静态成员变量的初始化,一般是在类外进行的,如果没有自己初始化的话,其实是将值静态成员变量默认的初始值就是零了,原因分析:因为静态成员变量是被存储在静态存储区域(全局存储区域)的所有的没有初始化的值,编译器都是自动给他们赋值为零。
静态成员函数和普通函数的区别
(1)关键字 static 的区别,
(2)静态成员函数实际就是一个类内的全局函数,不依赖于对象,而是依赖于类,而普通的成员函数则是依赖于类内的一个对象,
(3)静态成员函数只能访问类中的静态成员变量和成员函数,普通的成员函数则是都可以访问类中所有的普通成员函数和成员变量
(4)静态成员函数不包含指向具体对象的指针(没有 this 指针),而普通成员函数包含一个指向具体对象的 this 指针,
注意:
this指针是编译器自动将对象本身的的地址传递到类内的函数使用,传递给this。this指针的作用域是在类的内部,记住this 指针只有在类的普通成员函数,静态成员函数是绝对没有this 指针,
存储空间的分配:
class A { private: int i; int j; short a; short b; }; class B { private: int i; int j; short a; short b; static int c; }; class C { private: int i; int j; short a; short b; static int c; // 全局数据区(静态存储区) public: C() // 函数的部分是栈空间 { } ~C() { } }; int C::c = 10;
三个类,分配空间的大小, 都是12个字节,原因是静态成员变量不是在对象内进行分配的,而是被分配在全局数据区(静态存储区域),而函数不管是不是静态都是在代码段。
类内的成员变量的内存分布和结构体的类似,也是需要进行内存对齐的,这一点可以去学习结构体的对齐。