Ⅳ. 静态成员(static)
0x00 引入 - 计算类中创建了多少个类对象
如果我们要计算一个类中创建了多少个类对象,我们可以用 count 计算一下。
int count = 0; // 全局变量 class A { public: A(int a = 0) : _a(a) { count++; } A(const A& aa) : _a(aa._a) { count++; } private: int _a; }; void f(A a) { ; } int main(void) { A a1; A a2 = 1; f(a1); cout << count << endl; return 0; }
❓ 如果我不想让这个 count 可以被人在外面随便改呢?
int main(void) { A a1; A a2 = 1; f(a1); cout << cnt << endl; count++; // 我可以在类外修改它 return 0; }
有没有办法可以把 count 和类贴合起来呢?让这个 count 专门用来计算我 A 这个类的。
我们先试着把它定义成 —— 成员变量:
class A { public: A(int a = 0) : _a(a) { _count++; } A(const A& aa) : _a(aa._a) { _count++; } private: int _a; int _count = 0; // 定义成成员变量 };
但是这样还是不行!这样的话每个对象里面都有一个 count,
我们是希望的是每个对象创建的时候去++的是同一个变量,而不是每个对象里面都有一个。
那该怎么办呢?
类里面可以定义静态成员,在成员变量前面加一个 static,就是静态成员。
我们继续往下看 ~
0x01 静态成员的概念
声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称为静态成员变量。
用 static 修饰的成员函数,称为静态成员函数,静态的成员变量一定要在类外进行初始化。
class A { public: A(int a = 0) : _a(a) { _sCount++; } A(const A& aa) : _a(aa._a) { _sCount++; } private: int _a; // 静态成员变量属于整个类,所有对象,生命周期在整个程序运行期间。 static int _sCount; // 这里以 _s 为前缀,是为了一眼就看出它是静态成员变量。 };
0x02 静态成员的特性
① 静态成员为所有类对象所共享,不属于某个具体的实例。
② 静态成员变量必须在类外定义,定义时不添加 static 关键字。
③ 类静态成员即可用类名 :: 静态成员变量或者对象 . 来访问。
④ 静态成员函数没有隐藏的 this 指针,不能访问任何非静态成员。
⑤ 静态成员和类的普通成员一样,也有 public、protected、private 三种访问级别,也可以具有返回值。
0x03 静态成员函数的访问
💬 如果它是公有的,我们就可以在类外对它进行访问:
class A { public: A(int a = 0) : _a(a) { _sCount++; } A(const A& aa) : _a(aa._a) { _sCount++; } // private: int _a; static int _sCount; }; void f(A a) { ; } int main(void) { A a1; A a2 = 1; f(a1); cout << A::_sCount << endl; // 使用类域对它进行访问 /* 这里不是说是在 a1 里面找,这里只是帮助他突破类域罢了 */ cout << a1._sCount << endl; cout << a2._sCount << endl; return 0; }
但是如果它是私有的,我们可以提供一个公有的成员函数。
我们写一个公有的 GetCount 成员函数,让它返回 _sCount 的值,
这样我们就可以在类外调用该函数,就可以访问到它了。
还有没有更好的方式?让我不用对象就可以访问到它呢?
💬 静态成员函数:
static int GetCount() { return _sCount; }
它的好处是没有 this 指针,它只能访问静态的成员变量。
当然,我们还可以用友元,但是未免有些没必要了。
Ⅴ. 内部类
0x00 内部类的概念
如果在 类中定义 类,我们称 是 的内部类。
class A { class B { ; }; };
0x01 内部类特性
此时这个内部类是一个独立的类,它不属于外部类,
更不能通过外部类的对象去调用内部类,外部类对内部类没有任何特权。
但是,内部类就是外部类的友元类,
内部类可以通过外部类的对象参数来访问外部类中的所有成员,像极了殖民行为。
💬 B 是 A 的内部类:
class A { private: static int _s_a1; int _a2; public: class B { // B天生就是A的友元 public: void foo(const A& a) { cout << _s_a1 << endl; // ✅ cout << a._a2 << endl; // ✅ } private: int _b1; }; };
0x02 详细探索内部类
❓ 我们用 sizeof 计算 A 类的大小,得到的结果会是什么?
#include <iostream> using namespace std; class A { private: static int _s_a1; int _a2; public: class B { private: int _b1; }; }; int A::_s_a1 = 1; int main(void) { cout << "A的大小为: " << sizeof(A) << endl; return 0; }
① 内部类 B 和在全局定义是基本一样的,它只是受外部类 A 类域的限制,定义在 A 的类域中。
class A { private: static int _s_a1; int _a2; public: class B { private: int _b1; }; }; int A::_s_a1 = 1; int main(void) { A aa; A::B bb; // 用A的类域指定即可(前提是公有的) return 0; }
② 内部类 B 天生就是外部类 A 的友元,也就是 B 中可以访问 A 的私有,A 不能访问 B 的私有(或保护)。
所以,A 类型的对象里没有 B,跟 B 没什么关系,计算 sizeof 当然也不会带上B。
💬 舔的好!那我就勉为其难地,让你做我的朋友吧:
class A { private: static int _s_a1; int _a2; public: class B { // B天生就是A的友元 friend class A; // 声明A是B的友元 private: int _b1; }; };
如此一来,A 和 B 就互通了。