Chapter 3 Class¶
1 Point¶
C :数据和函数分开,通过普通函数操作对象
typedef struct point {
int x;
int y;
} Point;
// 通过 const Point* 传入对象地址,避免拷贝对象
void print(const Point* p) {
// 通过指针访问结构体成员
printf("%d %d\n", p->x, p->y);
}
void move(Point* p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
Point a;
Point b;
a.x = b.x = 1;
a.y = b.y = 1;
move(&a, 2, 2);
print(&a);
print(&b);
C++ :对象把属性和行为封装在一起,调用形式更自然
class Point {
public:
void init(int x, int y);
void move(int dx, int dy);
void print() const;
private:
int x;
int y;
};
void Point::init(int ix, int iy) {
x = ix;
y = iy;
}
void Point::move(int dx, int dy) {
x += dx;
y += dy;
}
void Point::print() const {
cout << x << ' ' << y << endl;
}
Point a;
a.init(1, 2);
a.move(2, 2);
a.print();
Objects = Attributes + Services
- Data:对象的属性、状态(properties / status)
- Operations:对象提供的操作、功能(functions)

2 this 指针¶
每个非静态成员函数都有一个隐藏参数(hidden parameter)this,可以理解为指向当前对象的指针。
成员函数可看作带对象指针参数的普通函数
void Stash::initialize(int sz);
可以理解为:
void Stash::initialize(Stash* this, int sz);
调用成员函数时必须指定对象
Stash a;
a.initialize(10);
可以理解为:
Stash::initialize(&a, 10);
this:指向调用该函数的对象
- 在成员函数内部,可以直接使用
this this指向“当前正在调用该成员函数的那个对象”- 它是成员函数天然拥有的局部变量,不能自己定义,但可以直接使用
对象(Object)
- 在 C++ 中,对象本质上就是一个变量,其最纯粹的定义是一块存储区域(a region of storage)
- 前面提到的结构体变量,在 C++ 中也都是对象
3 Ticket Machine Example¶
售票机问题描述
- 当顾客投入了正确金额后,售票机会打印车票
- 顾客先向机器中投入钱,再请求打印车票
- 机器在运行过程中,会持续累计自己收到的总金额
面向过程(Procedure-Oriented)地描述买票流程
- Step to the machine
- Insert money into the machine
- The machine prints a ticket
- Take the ticket and leave
我们可以写一个程序去模拟买票流程这件事,这样的程序可以运行,但并没有真正表示出那台机器本身,因而难以继续扩展和进一步开发。
售票机应被看作一个对象,它包含以下内容:

class TicketMachine {
// 对外提供服务的接口
public:
void showPrompt();
void getMoney();
void printTicket();
void showBalance();
void printError();
// 对象内部状态,不希望外部直接改动
private:
const int PRICE;
int balance;
int total;
};
Object vs. Class
- Objects:表示具体事物或事件,在运行时响应消息
- Classes:定义实例有哪些属性,在 C++ 中扮演类型(type)的角色

OOP Characteristics
- Everything is an object.
- A program is a bunch of objects telling each other what to do by sending messages.
- Each object has its own memory made up of other objects.
- Every object has a type.
- All objects of a particular type can receive the same messages.
类的定义方式
- 在 C++ 中,通常使用分离的
.h和.cpp文件来定义一个类 - 类声明与成员函数原型写在头文件(
.h)中 - 成员函数函数体写在源文件(
.cpp)中 - PImpl technique 有争议,主要作用是隐藏私有成员并减少编译依赖
4 Scope Resolution Operator ::¶
:: 解析符(resolver)
<ClassName>::<functionName>:表示某个类的成员函数定义或访问::<functionName>:表示全局作用域中的名字
作用域解析示例
void S::f() {
::f(); // 否则会递归调用成员函数 f()
::a++; // 选择全局变量 a
a--; // 这里的 a 是类作用域中的 a
}
编译单元(Compilation unit)
- 编译器每次只看一个
.cpp文件,并生成一个.obj目标文件 - 链接器(linker)再把所有
.obj文件链接成一个可执行文件 - 如果想让其他
.cpp文件知道某个函数或类的信息,需要使用.h头文件提供声明
5 The Header Files¶
- 如果一个函数声明在头文件里,那么:
- 函数被使用的地方必须包含这个头文件
- 函数被定义的地方也必须包含这个头文件
- 如果一个类声明在头文件里,那么:
- 类被使用的地方必须包含这个头文件
- 类成员函数被定义的地方也必须包含这个头文件
Header = Interface
- 头文件是你与代码使用者之间的一份契约(contract)
- 编译器通过“先声明,后使用”的规则来强制执行这份契约
- 所有结构、函数在使用前都必须先声明
6 Structure of C++ Program¶
C++ 程序的基本组织结构
.h文件中放 declarations(声明).cpp文件中放 definitions(定义).cpp通过#include把.h的内容插入进来- 预处理(after pre-compiler / preprocessor)后,头文件内容会被展开到对应的
.cpp中 - 其他模块如果要使用这些函数,也会通过
#include包含同一个头文件

Declarations vs. Definitions
- 一个
.cpp文件就是一个 compile unit .h中不放普通定义,只放声明(declarations),如:extern变量声明- 函数原型(function prototypes)
class/struct声明
#include
#include 会把被包含文件的内容插入到当前 .cpp 中 #include 所在的位置
#include "xx.h"
#include <xx.h>
#include "xx.h":通常先在当前目录查找,具体行为与实现有关#include <xx.h>:在编译器指定的目录中查找
标准头文件保护结构
#ifndef HEADER_FLAG
#define HEADER_FLAG
// Type declaration here...
#endif // HEADER_FLAG
头文件编写建议
- 一个头文件只放一个类声明
- 头文件名通常与对应的
.cpp同名 - 头文件内容要用
#ifndef/#define/#endif包围起来