📄 一句话概括
类成员 = 成员变量 + 成员函数,但除了这两个"普通居民",类里还有几个特殊身份的成员:内联成员函数(写在类里的小函数,就地展开)、静态成员(属于类、不属于某个对象,所有对象共享一份)、隐藏的 this 指针(成员函数里那个"当前对象"的地址,是"成员函数怎么知道在操作谁"的答案)。此外还有两种"住在里面的类":嵌套类(类里定义的类)和局部类(函数里定义的类)。本节先把地图铺开,后面六节逐个说清。
📝 本节和前面几节的关系
10.1~10.3 讲完了"对象的一生"(造出来、复制、销毁)。本节开始回头看细节:类里面到底有哪些东西、它们各自有哪些脾气。这一组会反复用到你已经很熟的老知识——static(6.7.2)、内联(6.6)、作用域(6.4),只是把它们从"函数里"搬到"类里"。你会发现:类里没有新概念,只有"同样概念的新位置"。
一、成员的两大阵营
| 阵营 | 成员 | 关键特点 |
|---|---|---|
| 每个对象各有一份 | 普通成员变量 | a.x 和 b.x 是两块不同的内存(10.1.1) |
| 整个类只有一份 | 静态成员变量(10.4.3) | Point::count,所有对象共享 |
| 跟着对象走 | 普通成员函数(含内联、const 成员函数) |
必须用对象来调:p.show() |
| 不跟对象走 | 静态成员函数(10.4.3) | 用类名就能调:Point::getCount() |
一句话记住这个分界:
"这个成员,是要'每个对象一份',还是'全类共用一份'?" 前者是普通成员,后者是静态成员。
二、本节路线图
| 小节 | 讲什么 | 一句话 |
|---|---|---|
| 10.4.1 访问类成员 | 怎么碰成员 | 对象用 .、指针用 ->;类内互相调不用带对象名;const 成员函数的用法 |
| 10.4.2 内联成员函数 | 写在类里的函数 | 默认就是内联——就地展开,省一次函数调用 |
| 10.4.3 静态类成员 | 属于类不属于对象 | static 成员变量要在类外定义;静态成员函数没有 this |
| 10.4.4 隐藏的 this 指针 | "当前对象"是谁 | 成员函数偷偷摸摸收了一个"自己的地址"参数,这就是 this |
| 10.4.5 嵌套类 | 类里定义的类 | 像"抽屉里的抽屉",外面要写 Outer::Inner |
| 10.4.6 局部类 | 函数里定义的类 | 只在那个函数里能用的类,几乎不用,认得就行 |
三、先建立直觉:类成员就像"公司里的职位"
| 类里的东西 | 公司里的对应 |
|---|---|
| 普通成员变量 | 每个员工的私人储物柜——各有一份 |
| 静态成员变量 | 公司公告栏——全公司就一块,谁都能看 |
| 普通成员函数 | 员工能做的事——必须"某个员工"去做 |
const 成员函数 |
只查看不改动的事(查工资条不算修改记录) |
| 静态成员函数 | 公司层面的事(比如"统计公司总人数"),不需要指定某个员工 |
this 指针 |
"我正在办的是谁的事" 这个自知道 |
| 嵌套类 | 部门里的内部小组——外面要写"某部门的小组"才提得到 |
有了这个直觉,后面六节读起来会顺很多。
四、动手 Demo:四种成员各来一个
#include <iostream>
using namespace std;
class Company {
private:
int salary; // 普通成员:每人一份
static int total; // 静态成员:全公司一份(10.4.3)
public:
Company(int s) : salary(s) {
total += s; // 静态成员可以直接用
}
// 普通成员函数:必须用对象调
void showSalary() const { // const 成员函数:承诺不改数据(10.4.1)
cout << "我的工资 = " << salary << endl;
}
// 静态成员函数:不需要对象也能调
static int getTotal() { // 注意:没有 this,不能碰 salary
return total;
}
};
int Company::total = 0; // ★ 静态成员必须在类外"定义"一次(10.4.3)
int main() {
Company a(3000);
Company b(5000);
a.showSalary(); // 我的工资 = 3000
b.showSalary(); // 我的工资 = 5000
cout << "全公司总工资 = " << Company::getTotal() << endl; // 8000,用类名调
cout << "也能用对象调 = " << a.getTotal() << endl; // 8000
return 0;
}
看到什么算成功:
我的工资 = 3000
我的工资 = 5000
全公司总工资 = 8000
也能用对象调 = 8000
读结果:
a和b的salary互不干扰(3000 / 5000)——普通成员每人一份。total两个对象共建共享(8000)——静态成员全类一份。getTotal()可以用Company::直接调——静态成员函数不依赖某个对象。
注意最后一行那个"也能用对象调":直接用 Company::getTotal() 更清楚,说明这个函数和具体对象无关。看到能这么调的成员,就知道它是 static 的。
五、常见误区
- "类成员只有成员变量和成员函数"——分类上是的,但成员函数又有好几个变体(
const成员函数、内联、静态),成员变量也有(静态)。把它们当成"同一类东西的不同性格",而不是新概念。 - "静态成员也是每个对象一份"——不是。静态成员属于类,全类只有一份(10.4.3 细讲)。判据:所有对象看到的必须是同一个值吗? 是,就用 static。
- "这些高级特性都要用上才算会写类"——完全相反。日常写的类,九成只用到普通成员 + 构造函数 + 析构函数。静态成员、嵌套类这些是在特定问题上才需要的工具。先明白"什么时候需要",比记住语法更重要。
- "
const成员函数和const成员变量是一回事"——不是。const成员变量指"这个数据不能改"(10.2.1 的初始化列表);const成员函数指"这个函数承诺不修改对象的数据"(10.4.1)。一个管数据,一个管函数。
自测三问(点开对答案)
1. 类成员分两大阵营,怎么判?——问一句:"**这个成员是每个对象一份,还是全类共用一份?**" 前者是**普通成员**(普通成员变量、普通成员函数),后者是**静态成员**(`static`)。 2. 静态成员函数和普通成员函数,调用方式有什么不同?——**普通成员函数必须用对象调**(`p.show()`);**静态成员函数可以用类名直接调**(`Point::getCount()`),因为它不依赖具体对象。 3. `const` 成员函数是在形容什么?——形容**"这个函数不会修改对象的数据"**(它是一个承诺)。**对象是 `const` 时,只能调用 `const` 成员函数**(10.4.1 讲原因)。- ☐ 10.4.1 访问类成员(下一节)