13. 封装与访问控制——编程世界的数据“守护者”

13.1 封装的概念

封装是面向对象编程的三大特性之一,它就像是一个坚固的“盒子”,将数据(属性)和操作这些数据的函数(方法)捆绑在一起,形成一个独立的单元,也就是类。封装的主要目的是隐藏对象的内部实现细节,只向外部提供必要的接口,这样可以提高代码的安全性和可维护性。

例如,在一个银行账户系统中,账户的余额是一个重要的数据,我们不希望外部代码直接修改这个余额,而是通过特定的方法(如存款、取款)来操作它。这就是封装的体现,将账户余额这个数据封装在账户类中,只提供安全的操作接口给外部使用。

13.2 访问控制的重要性

访问控制是实现封装的重要手段,它通过访问修饰符来限制对类的成员(数据成员和成员函数)的访问权限。合理的访问控制可以防止外部代码意外或恶意地修改类的内部数据,保证数据的完整性和安全性。同时,也有助于将类的接口和实现分离,使得类的使用者只需要关注类提供的接口,而不需要了解类的内部实现细节。

13.3 C++ 中的访问修饰符

在 C++ 中,有三种主要的访问修饰符:publicprivateprotected

13.3.1 public(公有)

公有成员可以在类的外部直接访问。通常,类的接口(成员函数)会被声明为公有,以便外部代码可以调用这些函数来与对象进行交互。

#include <iostream>
using namespace std;

class Rectangle {
public:
    // 公有数据成员
    double length;
    double width;

    // 公有成员函数
    double getArea() {
        return length * width;
    }
};

int main() {
    Rectangle rect;
    // 直接访问公有数据成员
    rect.length = 5.0;
    rect.width = 3.0;
    // 调用公有成员函数
    cout << "矩形的面积是: " << rect.getArea() << endl;
    return 0;
}

在这个示例中,lengthwidthgetArea 都是公有成员,在 main 函数中可以直接访问和调用。

13.3.2 private(私有)

私有成员只能在类的内部访问,外部代码无法直接访问。通常,类的数据成员会被声明为私有,通过公有成员函数来间接访问和修改这些数据成员,以保证数据的安全性。

#include <iostream>
using namespace std;

class Rectangle {
private:
    // 私有数据成员
    double length;
    double width;

public:
    // 公有成员函数,用于设置长度
    void setLength(double len) {
        if (len > 0) {
            length = len;
        } else {
            cout << "长度必须为正数!" << endl;
        }
    }

    // 公有成员函数,用于设置宽度
    void setWidth(double wid) {
        if (wid > 0) {
            width = wid;
        } else {
            cout << "宽度必须为正数!" << endl;
        }
    }

    // 公有成员函数,用于计算面积
    double getArea() {
        return length * width;
    }
};

int main() {
    Rectangle rect;
    // 通过公有成员函数设置长度和宽度
    rect.setLength(5.0);
    rect.setWidth(3.0);
    // 调用公有成员函数计算并输出面积
    cout << "矩形的面积是: " << rect.getArea() << endl;
    return 0;
}

在这个示例中,lengthwidth 是私有数据成员,main 函数无法直接访问它们,只能通过 setLengthsetWidth 这两个公有成员函数来间接设置它们的值。

13.3.3 protected(受保护)

受保护成员在类的内部和派生类(子类)中可以访问,在类的外部不能直接访问。受保护成员主要用于在继承关系中,让派生类可以访问基类的某些成员。

#include <iostream>
using namespace std;

// 基类
class Shape {
protected:
    // 受保护数据成员
    double area;

public:
    // 公有成员函数,用于计算面积(这里只是示例,没有具体实现)
    virtual void calculateArea() = 0;

    // 公有成员函数,用于输出面积
    void displayArea() {
        cout << "面积是: " << area << endl;
    }
};

// 派生类
class Rectangle : public Shape {
private:
    double length;
    double width;

public:
    Rectangle(double len, double wid) : length(len), width(wid) {}

    // 实现基类的纯虚函数
    void calculateArea() override {
        area = length * width;
    }
};

int main() {
    Rectangle rect(5.0, 3.0);
    rect.calculateArea();
    rect.displayArea();
    return 0;
}

在这个示例中,areaShape 类的受保护数据成员,Rectangle 类作为 Shape 类的派生类,可以访问 area 成员并对其进行赋值操作。

13.4 封装与访问控制的优点

  • 数据安全性:通过将数据成员声明为私有,外部代码无法直接访问和修改这些数据,只能通过类提供的公有成员函数进行操作,从而避免了数据被非法修改的风险。
  • 代码可维护性:封装使得类的内部实现细节被隐藏起来,当类的内部实现发生变化时,只要类的接口不变,外部代码就不需要进行修改,降低了代码的耦合度,提高了代码的可维护性。
  • 代码复用性:封装后的类可以作为一个独立的单元被复用,其他代码可以通过类提供的接口来使用这个类,而不需要关心类的内部实现细节。

13.5 课后小练习

  1. 定义一个表示银行账户的类 BankAccount,包含私有数据成员 accountNumber(账号)、balance(余额),公有成员函数 deposit(存款)、withdraw(取款)、getBalance(获取余额),通过访问控制保证账户余额的安全性。
  2. 定义一个表示图书的类 Book,包含私有数据成员 title(书名)、author(作者)、price(价格),公有成员函数 setTitlesetAuthorsetPrice 用于设置相应的信息,displayInfo 用于输出图书的信息,通过封装和访问控制实现数据的安全管理。

通过这部分的学习,你了解了封装和访问控制的概念、C++ 中的访问修饰符以及它们的优点。封装和访问控制是面向对象编程中非常重要的特性,能够帮助你编写出更加安全、可维护和可复用的代码。

类似文章

发表回复