1. 封装概念
封装是面向对象编程的三大特性之一,将数据(成员变量)和操作数据的方法(成员函数)捆绑在一起,形成一个"类"。通过访问控制修饰符隐藏内部实现细节,仅暴露必要的接口。
2. 访问控制修饰符
-
public:公有成员,类外部可直接访问
-
private:私有成员,仅类内部可访问(默认)
-
protected:保护成员,类内部和派生类可访问
3. 基本实现示例
class BankAccount {
private:
double balance; // 私有数据成员
std::string accountNumber;
bool isValidAmount(double amount) { // 私有方法
return amount > 0;
}
public:
// 公有接口
BankAccount(std::string accNum, double initialBalance)
: accountNumber(accNum), balance(initialBalance) {}
void deposit(double amount) {
if (isValidAmount(amount)) {
balance += amount;
}
}
bool withdraw(double amount) {
if (isValidAmount(amount) && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
double getBalance() const { // 只读访问
return balance;
}
};
4. 封装的优点
-
数据隐藏:保护内部数据不被意外修改
-
接口稳定:内部实现变化不影响外部调用
-
易于维护:修改实现不影响使用该类的代码
-
增强安全性:通过验证逻辑保证数据完整性
5. Getter/Setter 模式
class Person {
private:
std::string name;
int age;
public:
// Getter方法
std::string getName() const { return name; }
int getAge() const { return age; }
// Setter方法(可添加验证逻辑)
void setName(const std::string& newName) {
if (!newName.empty()) {
name = newName;
}
}
void setAge(int newAge) {
if (newAge >= 0 && newAge <= 150) {
age = newAge;
}
}
};
6. 设计原则
-
将数据成员设为private
-
通过公有成员函数提供接口
-
避免返回私有数据成员的引用或指针
-
对需要修改的成员提供setter,对需要读取的成员提供getter
-
构造函数用于初始化,避免在外部设置初始状态
7. 封装的实际意义
封装不仅仅是语法层面的数据隐藏,更重要的是:
-
建立清晰的类接口契约
-
分离"做什么"(接口)和"怎么做"(实现)
-
降低模块间的耦合度
-
提高代码的可测试性和可重用性
核心要点:通过封装,类的使用者只需要知道类能做什么,而不需要知道类如何做,这大大简化了代码的使用和维护。