代码仓库shanchuann/CPP-Learninng
封装的核心概念
封装是面向对象编程( OOP )的三大特性之一(另外两个是继承和多态),其核心思想是将数据(属性)和操作数据的方法(行为)绑定为一个独立的单元(类),并通过访问控制隐藏内部实现细节,仅对外提供可控的接口。这种设计模式确保了数据的安全性、代码的可维护性和可扩展性。
封装的两层含义:
- 数据与行为的结合
将描述对象状态的成员变量(如圆的半径)和操作这些变量的成员函数(如计算面积)组合在同一个类中,形成逻辑上的整体。例如:
1 2 3 4 5 6 7
| class Circle { private: double radius; public: void setRadius(double r) { radius = r; } double getArea() { return 3.14 * radius * radius; } };
|
- 访问控制与信息隐藏
通过访问修饰符(public、protected、private)控制成员的可见性,强制外部代码只能通过公共接口交互,避免直接操作内部数据。例如:
1 2 3 4 5 6 7
| class Person { private: int age; public: void setAge(int a) { if (a > 0) age = a; } int getAge() const { return age; } };
|
访问控制的深度解析
C++提供三种访问修饰符,精确控制类成员的访问范围:
| 修饰符 |
类内访问 |
类外访问 |
派生类访问 |
public |
✅ |
✅ |
✅ |
protected |
✅ |
❌ |
✅(仅限子类) |
private |
✅ |
❌ |
❌ |
实践建议:
- 默认私有原则:所有成员默认设为
private,仅将必要的接口暴露为public。
- 数据私有化:成员变量必须为
private,通过getter/setter控制访问,确保数据合法性。
- 审慎使用
protected:仅在明确需要子类直接访问时使用,避免破坏封装。
示例:通过访问控制实现读写权限细分
1 2 3 4 5 6 7 8 9 10 11
| class Person { public: void setName(const string& n) { name = n; } string getName() const { return name; } int getAge() const { return age; } void setPassword(const string& p) { password = p; } private: string name; int age = 0; string password; };
|
封装的关键技术实现
类的声明与实现分离
将类的声明(接口)放在头文件(.h),实现(细节)放在源文件(.cpp),降低编译依赖。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Person { public: void setName(const string& n); string getName() const; private: string name; };
#include "Person.h" void Person::setName(const string& n) { name = n; } string Person::getName() const { return name; }
|
友元函数与友元类
允许特定外部函数或类访问私有成员,需谨慎使用以避免破坏封装。
1 2 3 4 5 6 7 8 9
| class Rectangle { private: int width, height; friend int getArea(const Rectangle& r); };
int getArea(const Rectangle& r) { return r.width * r.height; }
|
RAII (资源获取即初始化)
通过构造函数获取资源,析构函数释放资源,确保异常安全。例如:
1 2 3 4 5 6 7 8 9 10
| class FileHandle { public: FileHandle(const string& filename) { file = fopen(filename.c_str(), "r"); if (!file) throw runtime_error("Open failed"); } ~FileHandle() { if (file) fclose(file); } private: FILE* file; };
|
高级封装技巧
Pimpl Idiom (指针指向实现)
将私有成员隐藏在实现类中,头文件仅保留指针,减少编译依赖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Widget { public: Widget(); ~Widget(); void doSomething(); private: class Impl; unique_ptr<Impl> pImpl; };
class Widget::Impl { public: int data; void process() { } };
Widget::Widget() : pImpl(make_unique<Impl>()) {} Widget::~Widget() = default; void Widget::doSomething() { pImpl->process(); }
|
委托构造函数( C++11 )
构造函数间相互调用,简化代码:
1 2 3 4 5 6 7 8
| class Employee { public: Employee(string n, int a) : name(n), age(a) { } Employee(string n) : Employee(n, 0) { } private: string name; int age; };
|