8.1 类、对象与封装
面向对象编程把程序看成一组互相协作的对象。对象保存状态,也提供行为。类是蓝图,描述每个对象拥有哪些状态,以及允许对这些状态执行哪些操作。
在 C++ 中,class 通常把数据保持为私有,只暴露少量清晰的公共接口。这一点在 C++ 里尤其重要,因为对象经常管理资源:内存、文件、句柄、网络连接、锁,以及其他必须保持有效的东西。
第一个类
下面的 BankAccount 类和 Java、Python OOP 章节中的例子类似,但 C++ 的细节更严格。字段通常称为数据成员,方法通常称为成员函数,访问标签 public: 和 private: 控制谁能使用这些名字。
cpp
#include <iostream>
#include <string>
class BankAccount {
public:
std::string owner;
std::string number;
double balance;
void deposit(double amount) {
balance += amount;
}
void withdraw(double amount) {
balance -= amount;
}
};
int main() {
BankAccount account;
account.owner = "Alice";
account.number = "6250941006528599";
account.balance = 50;
account.deposit(100);
std::cout << account.balance << std::endl;
return 0;
}这段代码可以运行,但它太开放了。任何外部代码都可以写 account.balance = -1000000;。这意味着对象无法保护自己的规则。
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
封装
封装意味着把表示细节留在类内部,强制外部代码使用受控操作。在 C++ 中,class 的成员默认就是 private。很多团队仍然会显式写出 private:,让设计更容易扫描。
cpp
class BankAccount {
private:
std::string owner_;
std::string number_;
double balance_;
public:
BankAccount(std::string owner, std::string number, double balance)
: owner_(owner), number_(number), balance_(balance) {}
double balance() const {
return balance_;
}
bool deposit(double amount) {
if (amount <= 0) {
return false;
}
balance_ += amount;
return true;
}
bool withdraw(double amount) {
if (amount <= 0 || amount > balance_) {
return false;
}
balance_ -= amount;
return true;
}
};外部代码可以查询余额,也可以请求存款或取款,但不能直接给 balance_ 赋值。类自己维护不变量:“余额只能通过经过验证的操作改变。”
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
成员函数、const 与 this
成员函数运行时有一个当前对象。在成员函数内部,隐藏指针 this 指向这个对象。平时很少需要显式写 this,但它解释了为什么 account.deposit(100) 知道要更新哪一个账户。
cpp
bool deposit(double amount) {
if (amount <= 0) {
return false;
}
this->balance_ += amount;
return true;
}带有 const 标记的成员函数承诺不会修改对象。这样它可以在 const 对象上调用,也让接口更容易推理。
cpp
double balance() const {
return balance_;
}
std::string owner() const {
return owner_;
}经验规则是:如果成员函数只是读取状态,就标记为 const;如果它会改变对象状态,就不要加 const,并且让函数名清楚表达这个修改。
正在加载概念检查...
正在加载本节练习...