类的成员不只是数据和函数:还能让自定义类型的对象像 int
一样用
+、==、<<,也能让某些成员属于”类”而不是某个对象。
📚 基本概念速读
| 名称 |
定义 |
省流 |
| 运算符重载(operator overloading) |
给自定义类型定义运算符的行为 |
对象也能加减比较 |
operator+ |
重载 + 运算符的成员函数 |
定义加法 |
operator<< |
重载输出运算符 |
对象直接 cout |
operator== |
重载相等比较 |
定义”相等” |
| 静态成员变量 |
属于类而不是某个对象的变量 |
全类共享一份 |
| 静态成员函数 |
不依赖具体对象、用类名调用的函数 |
类级操作 |
🧩 为什么需要运算符重载
没有运算符重载时,比较两个自定义对象要写函数调用:
1 2 3 4 5
| Point a{1, 2}; Point b{3, 4};
Point c = add(a, b);
|
运算符重载让自定义类型用起来像内置类型,代码更直观:
1 2 3
| Point c = a + b; if (a == b) { ... } cout << a << endl;
|
➕ 运算符重载基础
重载运算符的成员函数写法:operator 后跟运算符符号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <iostream> using namespace std;
class Point { private: int x, y;
public: Point(int px, int py) : x(px), y(py) {}
Point operator+(const Point& other) const { return Point(x + other.x, y + other.y); }
bool operator==(const Point& other) const { return x == other.x && y == other.y; }
int getX() const { return x; } int getY() const { return y; } };
int main() { Point a(1, 2); Point b(3, 4);
Point c = a + b; cout << c.getX() << " " << c.getY() << endl;
if (a == b) { cout << "相等" << endl; } else { cout << "不相等" << endl; } return 0; }
|
关键点:
operator+ 是成员函数,a + b 等价于调用
a.operator+(b),左操作数就是 this;
- 返回新对象而不是修改自身;
const 成员函数保证”比较/加法不修改对象”。
🖨️ 重载输出运算符 <<
<< 不能作为成员函数重载(左操作数是
cout,不是我们的类),要写成非成员函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> using namespace std;
class Point { private: int x, y;
public: Point(int px, int py) : x(px), y(py) {}
int getX() const { return x; } int getY() const { return y; } };
ostream& operator<<(ostream& out, const Point& p) { out << "(" << p.getX() << ", " << p.getY() << ")"; return out; }
int main() { Point p(1, 2); cout << p << endl; return 0; }
|
返回 ostream&
是为了支持链式输出:cout << p << " " << q。
🧮 重载下标运算符 []
容器类常用,比如让自定义类能像数组一样按下标访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class IntArray { private: int data[10];
public: int& operator[](int index) { return data[index]; } };
IntArray arr; arr[3] = 42; cout << arr[3] << endl;
|
🧱 静态成员变量
静态成员变量属于类,所有对象共享同一份,而不是每个对象各有一份。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> using namespace std;
class Counter { private: static int count;
public: Counter() { count++; }
static int getCount() { return count; } };
int Counter::count = 0;
int main() { Counter a; Counter b; Counter c;
cout << Counter::getCount() << endl; return 0; }
|
要点:
| 特性 |
普通成员变量 |
静态成员变量 |
| 归属 |
每个对象一份 |
整个类共享一份 |
| 访问 |
通过对象 |
通过类名 类名::变量 或对象 |
| 定义 |
类内自动创建 |
需要在类外定义一次 |
⚙️ 静态成员函数
静态成员函数不依赖具体对象,用类名直接调用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MathUtils { public: static int square(int x) { return x * x; } };
int main() { int r = MathUtils::square(5); return 0; }
|
静态成员函数的限制:没有 this
指针,所以不能访问普通成员变量(不知道操作哪个对象的),只能访问静态成员和其他静态函数。
| 特性 |
普通成员函数 |
静态成员函数 |
| 依赖对象 |
是,有 this |
否,没有 this |
| 调用方式 |
对象调用 |
类名调用 |
| 能访问普通成员 |
能 |
不能 |
| 能访问静态成员 |
能 |
能 |
⚠️ 常见误区
| 误区 |
正解 |
| 运算符重载是给内置类型用的 |
内置类型运算符是固定的,重载只针对自定义类型 |
<< 重载必须是成员函数 |
<< 左操作数是流对象,要用非成员函数形式 |
重载 + 应该修改左操作数 |
通常返回新对象,a + b 不应改变 a |
| 静态成员变量每个对象一份 |
全类共享一份,且在类外定义一次 |
| 静态成员函数能访问普通成员变量 |
静态函数没有 this,只能访问静态成员 |
| 重载运算符可以随便改语义 |
应保持直觉语义(+ 是加法、==
是相等),别滥用 |
✅ 总结
运算符重载让自定义类型用起来像内置类型(+、==、<<、[]),静态成员让数据或操作属于类本身;两者的共同点是让类的表达力更强。
这一章补上了类与对象(第 7
章)之后的两块常用拼图。接下来无论是写容器类、工具类,还是做计数统计,都有了对应的语法。
Happy Hacking! 🎉