封装指将数据与操作数据的函数绑定,并隐藏实现细节,仅通过公开接口与外部交互。C++ 用 public、protected、private 访问说明符控制成员可见性。本节说明三类说明符的含义、通过成员函数维护不变量,以及友元与多文件组织的入门。

访问说明符

说明符类外访问派生类访问
public允许允许(对 public 基类成员)
protected不允许允许
private不允许不允许(除非友元)

class 内未写说明符的成员默认为 private;struct 默认为 public。

通过接口维护不变量

#include <iostream>

class Account {
public:
    void deposit(double amount) {
        if (amount > 0) {
            balance_ += amount;
        }
    }

    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance_) {
            balance_ -= amount;
            return true;
        }
        return false;
    }

    double balance() const { return balance_; }

private:
    double balance_ = 0.0;
};

int main() {
    Account a;
    a.deposit(100);
    std::cout << a.balance() << "\n";
    return 0;
}

典型输出:100。外部不能直接改 balance_,业务规则集中在成员函数内校验。

getter 与 setter

只读属性用 const 成员函数取出私有数据(getter);需要改写时,用另一组成员函数校验后再赋给私有成员(setter)。不是每个字段都要配 setter,很多类型只提供只读接口。

C++ getter 与 setter运行
#include <iostream>
#include <string>

class Person {
    std::string name_;
    int age_ = 0;
public:
    const std::string& name() const {   // getter:不修改对象
        return name_;
    }
    void set_name(const std::string& n) {
        if (!n.empty()) {
            name_ = n;
        }
    }
    int age() const {
        return age_;
    }
    void set_age(int a) {               // setter:拒绝不合理的年龄
        if (a >= 0 && a < 150) {
            age_ = a;
        }
    }
};

int main() {
    Person p;
    p.set_name("Ada");
    p.set_age(20);
    p.set_age(-1);   // 不合法,age_ 保持 20
    std::cout << p.name() << " " << p.age() << std::endl;
    return 0;
}

输出:

Ada 20

name()、age() 只读;set_name 拒绝空串,set_age(-1) 被丢掉,所以年龄仍是 20。类外不能写 p.age_ = -1。

protected 与继承

protected 成员对派生类可见、对外不可见,用于向子类开放扩展点而不破坏封装。在继承层次中设计基类接口时,宜区分 public API 与 protected 钩子函数。

友元(入门)

friend 函数或类可访问私有成员,有意破坏封装边界。适用于运算符重载、紧密耦合组件或测试夹具;应控制范围,避免大面积友元导致维护困难。

class Engine {
    friend void tune(Engine& e);
private:
    int rpm_ = 0;
};

接口与实现分离

头文件常只声明 public 接口;私有成员函数与复杂实现可放在 .cpp 源文件,缩短编译依赖,与头文件与多文件组织一致。PIMPL(指针指向实现)是进一步隐藏细节的惯用法,属进阶主题。

封装与多态

公开接口可设计为抽象基类(纯虚函数),实现细节藏在派生类 private 区,调用方仅依赖虚函数接口。这与数据成员的 private 封装互补。

本节说明了访问控制与封装意图。下一节介绍继承:基类与派生类及 public 继承语义。