Skip to content

C++ 数据封装

数据封装是指将数据和操作数据的方法绑定在一起,并隐藏对象的内部实现细节。它是面向对象编程的核心概念之一,通过类来实现。

1. 数据封装的基本概念

数据封装依赖于三个关键概念:

  1. 数据成员:存储对象的状态
  2. 成员函数:操作数据成员的方法
  3. 访问修饰符:控制对数据成员和成员函数的访问权限

1.1 示例

cpp
#include <iostream>

class Student {
private:
    std::string name;
    int age;
    float gpa;

public:
    Student(std::string name, int age, float gpa) 
        : name(name), age(age), gpa(gpa) {}
    
    void set_name(std::string name) {
        this->name = name;
    }
    
    std::string get_name() {
        return name;
    }
    
    void set_age(int age) {
        this->age = age;
    }
    
    int get_age() {
        return age;
    }
    
    void set_gpa(float gpa) {
        if (gpa >= 0.0f && gpa <= 4.0f) {
            this->gpa = gpa;
        }
    }
    
    float get_gpa() {
        return gpa;
    }
    
    void display() {
        std::cout << "姓名: " << name << std::endl;
        std::cout << "年龄: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
    }
};

int main() {
    Student student("张三", 20, 3.8f);
    
    student.display();
    
    student.set_name("李四");
    student.set_age(21);
    student.set_gpa(3.9f);
    
    student.display();
    
    return 0;
}

2. 访问修饰符

访问修饰符是实现数据封装的重要工具。

2.1 private 成员

private成员只能在类内部被访问,外部无法直接访问。

cpp
#include <iostream>

class BankAccount {
private:
    double balance;

public:
    BankAccount(double initial_balance) : balance(initial_balance) {}
    
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    
    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
    
    double get_balance() {
        return balance;
    }
};

int main() {
    BankAccount account(1000.0);
    
    account.deposit(500.0);
    account.withdraw(200.0);
    
    std::cout << "余额: " << account.get_balance() << std::endl;
    
    return 0;
}

2.2 public 成员

public成员可以在任何地方被访问。

cpp
#include <iostream>

class Point {
public:
    int x;
    int y;
    
    Point(int x, int y) : x(x), y(y) {}
    
    void print() {
        std::cout << "(" << x << ", " << y << ")" << std::endl;
    }
};

int main() {
    Point point(10, 20);
    
    point.x = 30;
    point.y = 40;
    
    point.print();
    
    return 0;
}

2.3 protected 成员

protected成员可以在类内部和派生类中被访问。

cpp
#include <iostream>

class Base {
protected:
    int x;

public:
    Base(int x) : x(x) {}
    
    void set_x(int x) {
        this->x = x;
    }
    
    int get_x() {
        return x;
    }
};

class Derived : public Base {
public:
    Derived(int x) : Base(x) {}
    
    void increment_x() {
        x++;
    }
};

int main() {
    Derived derived(10);
    
    derived.increment_x();
    
    std::cout << "x = " << derived.get_x() << std::endl;
    
    return 0;
}

3. Getter 和 Setter 方法

Getter 和 Setter 方法是访问和修改私有成员的标准方式。

3.1 基本用法

cpp
#include <iostream>

class Person {
private:
    std::string name;
    int age;

public:
    Person(std::string name, int age) : name(name), age(age) {}
    
    void set_name(std::string name) {
        this->name = name;
    }
    
    std::string get_name() {
        return name;
    }
    
    void set_age(int age) {
        if (age >= 0) {
            this->age = age;
        }
    }
    
    int get_age() {
        return age;
    }
};

int main() {
    Person person("张三", 20);
    
    std::cout << "姓名: " << person.get_name() << std::endl;
    std::cout << "年龄: " << person.get_age() << std::endl;
    
    person.set_name("李四");
    person.set_age(21);
    
    std::cout << "姓名: " << person.get_name() << std::endl;
    std::cout << "年龄: " << person.get_age() << std::endl;
    
    return 0;
}

4. 数据封装的好处

4.1 保护数据

cpp
#include <iostream>

class BankAccount {
private:
    double balance;

public:
    BankAccount(double initial_balance) : balance(initial_balance) {}
    
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    
    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
    
    double get_balance() {
        return balance;
    }
};

int main() {
    BankAccount account(1000.0);
    
    account.deposit(500.0);
    account.withdraw(200.0);
    
    account.deposit(-100.0);  // 无效操作
    account.withdraw(2000.0);  // 无效操作
    
    std::cout << "余额: " << account.get_balance() << std::endl;
    
    return 0;
}

4.2 提高代码的可维护性

cpp
#include <iostream>

class Temperature {
private:
    double celsius;

public:
    Temperature(double celsius) : celsius(celsius) {}
    
    void set_celsius(double celsius) {
        this->celsius = celsius;
    }
    
    double get_celsius() {
        return celsius;
    }
    
    void set_fahrenheit(double fahrenheit) {
        celsius = (fahrenheit - 32) * 5.0 / 9.0;
    }
    
    double get_fahrenheit() {
        return celsius * 9.0 / 5.0 + 32;
    }
    
    void set_kelvin(double kelvin) {
        celsius = kelvin - 273.15;
    }
    
    double get_kelvin() {
        return celsius + 273.15;
    }
};

int main() {
    Temperature temp(25.0);
    
    std::cout << "摄氏度: " << temp.get_celsius() << std::endl;
    std::cout << "华氏度: " << temp.get_fahrenheit() << std::endl;
    std::cout << "开尔文: " << temp.get_kelvin() << std::endl;
    std::cout << std::endl;
    
    temp.set_fahrenheit(77.0);
    
    std::cout << "摄氏度: " << temp.get_celsius() << std::endl;
    std::cout << "华氏度: " << temp.get_fahrenheit() << std::endl;
    std::cout << "开尔文: " << temp.get_kelvin() << std::endl;
    
    return 0;
}

5. 示例:综合运用

现在,让我们看一个综合运用数据封装特性的例子:

cpp
#include <iostream>
#include <string>

class Book {
private:
    std::string title;
    std::string author;
    double price;
    int quantity;

public:
    Book(std::string title, std::string author, double price, int quantity) 
        : title(title), author(author), price(price), quantity(quantity) {}
    
    void set_title(std::string title) {
        this->title = title;
    }
    
    std::string get_title() {
        return title;
    }
    
    void set_author(std::string author) {
        this->author = author;
    }
    
    std::string get_author() {
        return author;
    }
    
    void set_price(double price) {
        if (price > 0) {
            this->price = price;
        }
    }
    
    double get_price() {
        return price;
    }
    
    void set_quantity(int quantity) {
        if (quantity >= 0) {
            this->quantity = quantity;
        }
    }
    
    int get_quantity() {
        return quantity;
    }
    
    void add_quantity(int amount) {
        if (amount > 0) {
            quantity += amount;
        }
    }
    
    void sell_quantity(int amount) {
        if (amount > 0 && amount <= quantity) {
            quantity -= amount;
        }
    }
    
    double get_total_value() {
        return price * quantity;
    }
    
    void display() {
        std::cout << "书名: " << title << std::endl;
        std::cout << "作者: " << author << std::endl;
        std::cout << "价格: " << price << std::endl;
        std::cout << "数量: " << quantity << std::endl;
        std::cout << "总价值: " << get_total_value() << std::endl;
    }
};

int main() {
    Book book("C++ Primer", "Stanley B. Lippman", 89.0, 10);
    
    std::cout << "书籍信息:" << std::endl;
    book.display();
    std::cout << std::endl;
    
    book.add_quantity(5);
    std::cout << "添加 5 本后:" << std::endl;
    book.display();
    std::cout << std::endl;
    
    book.sell_quantity(3);
    std::cout << "卖出 3 本后:" << std::endl;
    book.display();
    std::cout << std::endl;
    
    book.set_price(99.0);
    std::cout << "更新价格后:" << std::endl;
    book.display();
    
    return 0;
}

小结

C++ 数据封装包括:

  1. 数据封装的基本概念

    • 数据成员:存储对象的状态
    • 成员函数:操作数据成员的方法
    • 访问修饰符:控制对数据成员和成员函数的访问权限
  2. 访问修饰符

    • private成员:只能在类内部被访问
    • public成员:可以在任何地方被访问
    • protected成员:可以在类内部和派生类中被访问
  3. Getter 和 Setter 方法

    • Getter 方法:获取私有成员的值
    • Setter 方法:设置私有成员的值
  4. 数据封装的好处

    • 保护数据:防止外部直接修改私有成员
    • 提高代码的可维护性:可以修改实现而不影响外部代码
    • 降低代码的耦合度:通过接口访问数据

关键概念:

  • 数据封装:将数据和操作数据的方法绑定在一起,并隐藏对象的内部实现细节
  • 数据成员:存储对象的状态
  • 成员函数:操作数据成员的方法
  • 访问修饰符:控制对数据成员和成员函数的访问权限
  • Getter 方法:获取私有成员的值
  • Setter 方法:设置私有成员的值

掌握数据封装是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的接口(抽象类)。