C++ 类访问修饰符(完整教程)

C++ 类访问修饰符:掌握封装的“安全锁”

在 C++ 的面向对象编程世界里,类(class)是构建复杂程序的核心单元。而类的成员——变量和函数——是否能被外部访问,决定了程序的健壮性与可维护性。这背后,正是 C++ 类访问修饰符 在默默发挥作用。它们就像一道道无形的门禁系统,控制着谁可以进入、谁只能观望。

如果你曾写过类,却发现自己不小心暴露了内部数据,或者被别人随意修改了关键变量,那么理解访问修饰符就不再是“加分项”,而是“必修课”。本文将带你从零开始,一步步掌握 publicprivateprotected 这三大访问控制关键字,让代码更安全、设计更优雅。


为什么需要访问修饰符?

想象你有一间私人书房,里面放着你的日记本、财务记录和未发表的小说草稿。你希望朋友能借阅你的书,但绝不能随意翻看你的日记。于是你设置了不同的门:公共书架(公开)、书柜锁(私有)、以及只对家人开放的抽屉(受保护)。

在 C++ 中,类就像是你的书房。public 成员是书架上的书,谁都可以看;private 成员是锁着的抽屉,只有你自己能打开;protected 则像是只对“家人”(派生类)开放的特殊通道。

没有访问修饰符,所有成员都默认为 private,但你仍然可以在类外通过 public 成员函数来间接访问。这种机制,就是封装(Encapsulation)的核心思想。


public:公开的“展示窗口”

public 是最开放的访问级别。声明为 public 的成员,可以在类的外部被任意访问,无论是其他函数、类,还是主函数。

#include <iostream>
using namespace std;

class Book {
public:
    // 公共成员变量:书名
    string title;

    // 公共成员函数:显示书名
    void displayTitle() {
        cout << "书名是: " << title << endl;
    }

    // 公共函数:设置书名
    void setTitle(string newTitle) {
        title = newTitle;
    }
};

int main() {
    Book myBook;

    // 直接访问 public 成员变量
    myBook.title = "C++ 编程入门";

    // 调用 public 成员函数
    myBook.displayTitle();  // 输出:书名是: C++ 编程入门

    // 修改书名
    myBook.setTitle("C++ 高级编程");
    myBook.displayTitle();  // 输出:书名是: C++ 高级编程

    return 0;
}

注意:虽然 public 很方便,但过度使用会破坏封装性。比如你直接修改 title,就失去了对数据的控制。如果未来想加校验逻辑(如禁止空字符串),就必须修改所有访问点。


private:私有的“保险箱”

private 是最严格的访问级别。声明为 private 的成员,只能在类内部被访问,包括类的成员函数和友元函数。外部代码完全无法直接读写。

#include <iostream>
using namespace std;

class BankAccount {
private:
    // 私有成员变量:账户余额
    double balance;

    // 私有成员函数:验证金额合法性
    bool isValidAmount(double amount) {
        return amount >= 0;
    }

public:
    // 构造函数:初始化余额
    BankAccount(double initialBalance) {
        if (isValidAmount(initialBalance)) {
            balance = initialBalance;
        } else {
            balance = 0;
            cout << "金额无效,余额设置为 0" << endl;
        }
    }

    // 公共函数:存款
    void deposit(double amount) {
        if (isValidAmount(amount)) {
            balance += amount;
            cout << "存款成功,当前余额: " << balance << endl;
        } else {
            cout << "存款金额不能为负数" << endl;
        }
    }

    // 公共函数:取款
    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "取款成功,当前余额: " << balance << endl;
        } else {
            cout << "取款失败:余额不足或金额无效" << endl;
        }
    }

    // 公共函数:查看余额(安全访问)
    void checkBalance() {
        cout << "当前账户余额: " << balance << endl;
    }
};

int main() {
    BankAccount account(1000.0);

    account.deposit(200.0);    // 正常存款
    account.withdraw(150.0);   // 正常取款
    account.checkBalance();    // 查看余额

    // 下面这行会报错!因为 balance 是 private
    // account.balance = -100;  // 错误:无法访问私有成员

    return 0;
}

关键点private 成员只有通过 public 成员函数才能被操作。这确保了数据的安全性与一致性。比如 deposit 函数内部会检查金额合法性,防止非法操作。


protected:受保护的“家族通道”

protectedprivatepublic 之间的中间地带。它允许类内部以及该类的派生类(子类) 访问成员。但在类外部,它和 private 一样无法访问。

这在继承体系中非常有用。比如你有一个 Vehicle 类,它有 protectedspeed 成员,子类 CarBike 就可以继承并使用它。

#include <iostream>
using namespace std;

class Vehicle {
protected:
    // 受保护成员:速度
    double speed;

public:
    // 构造函数
    Vehicle(double initialSpeed = 0) {
        speed = initialSpeed;
    }

    // 公共函数:设置速度
    void setSpeed(double newSpeed) {
        if (newSpeed >= 0) {
            speed = newSpeed;
        }
    }

    // 公共函数:获取速度
    double getSpeed() {
        return speed;
    }
};

// 派生类:Car
class Car : public Vehicle {
public:
    // Car 类可以访问 Vehicle 的 protected 成员
    void accelerate() {
        speed += 10;
        cout << "汽车加速,当前速度: " << speed << " km/h" << endl;
    }

    // 也可以调用父类的公共函数
    void showSpeed() {
        cout << "当前车速: " << getSpeed() << " km/h" << endl;
    }
};

// 派生类:Bike
class Bike : public Vehicle {
public:
    void pedal() {
        speed += 5;
        cout << "自行车蹬踏,当前速度: " << speed << " km/h" << endl;
    }
};

int main() {
    Car myCar;
    myCar.setSpeed(50);      // 通过公共接口设置速度
    myCar.accelerate();      // 子类使用 protected 成员
    myCar.showSpeed();

    Bike myBike;
    myBike.setSpeed(15);
    myBike.pedal();

    // 下面这行会报错!因为 speed 是 protected,不能在类外访问
    // myCar.speed = 100;     // 错误:无法访问受保护成员

    return 0;
}

形象比喻protected 就像家族企业中的“内部通道”——员工(子类)可以走,但外人(类外代码)必须走正门(public)。


三种访问修饰符对比

访问级别 类内部 派生类 类外部
public ✅ 可访问 ✅ 可访问 ✅ 可访问
private ✅ 可访问 ❌ 不可访问 ❌ 不可访问
protected ✅ 可访问 ✅ 可访问 ❌ 不可访问

重要提醒:在类中,如果没有显式指定访问修饰符,默认为 private。因此,所有未声明的成员默认都是私有的。


实际开发中的最佳实践

  1. 优先使用 private:把所有数据成员设为 private,通过 public 函数控制访问。
  2. 合理使用 protected:仅当派生类需要访问父类成员时才使用。
  3. 避免直接暴露数据:不要让外部直接修改成员变量。比如 account.balance = 1000; 是危险行为。
  4. 用函数封装逻辑:比如在 setBalance() 中加入校验、日志、事件通知等。
class Account {
private:
    double balance;

public:
    void setBalance(double newBalance) {
        if (newBalance < 0) {
            cout << "余额不能为负数" << endl;
            return;
        }
        balance = newBalance;
        cout << "余额已更新为: " << balance << endl;
    }

    double getBalance() const {
        return balance;
    }
};

const 关键字表示该函数不会修改对象状态,是良好习惯。


总结

C++ 类访问修饰符是构建健壮、可维护程序的基石。它们不仅控制了数据的可见性,更体现了“封装”的编程哲学。

  • public 提供开放接口,让外部可以安全交互;
  • private 锁住核心数据,防止意外破坏;
  • protected 在继承中架起桥梁,支持代码复用。

掌握它们,就像学会了如何设计一座安全又高效的城堡。每一扇门背后,都是对代码质量的承诺。

当你下次写类时,不妨先问自己:这个成员该放在“公开”、“私有”还是“受保护”的位置?答案,往往就在你对程序结构的理解之中。