Skip to content

C++ 数据抽象

数据抽象是指只向外界提供必要的信息,而隐藏具体的实现细节。它是面向对象编程的核心概念之一,通过抽象类和接口来实现。

1. 数据抽象的基本概念

数据抽象依赖于两个关键概念:

  1. 接口:提供对对象进行操作的函数集合
  2. 实现:接口的具体实现细节

1.1 示例

cpp
#include <iostream>

class Calculator {
public:
    int add(int a, int b) {
        return a + b;
    }
    
    int subtract(int a, int b) {
        return a - b;
    }
    
    int multiply(int a, int b) {
        return a * b;
    }
    
    int divide(int a, int b) {
        return a / b;
    }
};

int main() {
    Calculator calculator;
    
    std::cout << "10 + 20 = " << calculator.add(10, 20) << std::endl;
    std::cout << "10 - 20 = " << calculator.subtract(10, 20) << std::endl;
    std::cout << "10 * 20 = " << calculator.multiply(10, 20) << std::endl;
    std::cout << "20 / 10 = " << calculator.divide(20, 10) << std::endl;
    
    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) {
        balance += amount;
    }
    
    void withdraw(double amount) {
        if (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;
}

3. 抽象类

抽象类是包含至少一个纯虚函数的类,它不能被实例化,只能被继承。

3.1 抽象类的基本用法

cpp
#include <iostream>

class Shape {
public:
    virtual double area() = 0;
    virtual double perimeter() = 0;
};

class Circle : public Shape {
private:
    double radius;

public:
    Circle(double radius) : radius(radius) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() override {
        return 2 * 3.14159 * radius;
    }
};

class Rectangle : public Shape {
private:
    double width;
    double height;

public:
    Rectangle(double width, double height) : width(width), height(height) {}
    
    double area() override {
        return width * height;
    }
    
    double perimeter() override {
        return 2 * (width + height);
    }
};

int main() {
    Shape* shape;
    
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);
    
    shape = &circle;
    std::cout << "圆的面积: " << shape->area() << std::endl;
    std::cout << "圆的周长: " << shape->perimeter() << std::endl;
    
    shape = &rectangle;
    std::cout << "矩形的面积: " << shape->area() << std::endl;
    std::cout << "矩形的周长: " << shape->perimeter() << std::endl;
    
    return 0;
}

4. 数据抽象的好处

4.1 隐藏实现细节

cpp
#include <iostream>

class Stack {
private:
    int* data;
    int top;
    int capacity;

public:
    Stack(int size) : capacity(size), top(-1) {
        data = new int[capacity];
    }
    
    ~Stack() {
        delete[] data;
    }
    
    void push(int value) {
        if (top == capacity - 1) {
            std::cout << "栈已满" << std::endl;
            return;
        }
        data[++top] = value;
    }
    
    int pop() {
        if (top == -1) {
            std::cout << "栈为空" << std::endl;
            return -1;
        }
        return data[top--];
    }
    
    bool is_empty() {
        return top == -1;
    }
    
    bool is_full() {
        return top == capacity - 1;
    }
};

int main() {
    Stack stack(5);
    
    stack.push(10);
    stack.push(20);
    stack.push(30);
    
    while (!stack.is_empty()) {
        std::cout << stack.pop() << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

4.2 提高代码的可维护性

cpp
#include <iostream>

class Employee {
private:
    std::string name;
    double salary;

public:
    Employee(std::string name, double salary) : name(name), salary(salary) {}
    
    void set_name(std::string name) {
        this->name = name;
    }
    
    std::string get_name() {
        return name;
    }
    
    void set_salary(double salary) {
        if (salary >= 0) {
            this->salary = salary;
        }
    }
    
    double get_salary() {
        return salary;
    }
    
    void display() {
        std::cout << "姓名: " << name << std::endl;
        std::cout << "工资: " << salary << std::endl;
    }
};

int main() {
    Employee employee("张三", 10000.0);
    
    employee.display();
    
    employee.set_name("李四");
    employee.set_salary(12000.0);
    
    employee.display();
    
    return 0;
}

5. 示例:综合运用

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

cpp
#include <iostream>
#include <string>

class Database {
private:
    struct Node {
        std::string key;
        std::string value;
        Node* next;
        
        Node(std::string key, std::string value) 
            : key(key), value(value), next(nullptr) {}
    };
    
    Node* head;

public:
    Database() : head(nullptr) {}
    
    ~Database() {
        Node* current = head;
        while (current != nullptr) {
            Node* next = current->next;
            delete current;
            current = next;
        }
    }
    
    void insert(std::string key, std::string value) {
        Node* new_node = new Node(key, value);
        
        if (head == nullptr) {
            head = new_node;
        } else {
            Node* current = head;
            while (current->next != nullptr) {
                current = current->next;
            }
            current->next = new_node;
        }
    }
    
    std::string get(std::string key) {
        Node* current = head;
        while (current != nullptr) {
            if (current->key == key) {
                return current->value;
            }
            current = current->next;
        }
        return "";
    }
    
    void update(std::string key, std::string value) {
        Node* current = head;
        while (current != nullptr) {
            if (current->key == key) {
                current->value = value;
                return;
            }
            current = current->next;
        }
    }
    
    void remove(std::string key) {
        if (head == nullptr) {
            return;
        }
        
        if (head->key == key) {
            Node* temp = head;
            head = head->next;
            delete temp;
            return;
        }
        
        Node* current = head;
        while (current->next != nullptr) {
            if (current->next->key == key) {
                Node* temp = current->next;
                current->next = temp->next;
                delete temp;
                return;
            }
            current = current->next;
        }
    }
    
    void display() {
        Node* current = head;
        while (current != nullptr) {
            std::cout << current->key << ": " << current->value << std::endl;
            current = current->next;
        }
    }
};

int main() {
    Database db;
    
    db.insert("name", "张三");
    db.insert("age", "20");
    db.insert("city", "北京");
    
    std::cout << "数据库内容:" << std::endl;
    db.display();
    std::cout << std::endl;
    
    std::cout << "获取 name: " << db.get("name") << std::endl;
    std::cout << "获取 age: " << db.get("age") << std::endl;
    std::cout << std::endl;
    
    db.update("age", "21");
    std::cout << "更新 age 后:" << std::endl;
    db.display();
    std::cout << std::endl;
    
    db.remove("city");
    std::cout << "删除 city 后:" << std::endl;
    db.display();
    
    return 0;
}

小结

C++ 数据抽象包括:

  1. 数据抽象的基本概念

    • 接口:提供对对象进行操作的函数集合
    • 实现:接口的具体实现细节
  2. 访问修饰符

    • private成员:只能在类内部被访问
    • public成员:可以在任何地方被访问
  3. 抽象类

    • 包含至少一个纯虚函数的类
    • 不能被实例化,只能被继承
  4. 数据抽象的好处

    • 隐藏实现细节
    • 提高代码的可维护性
    • 降低代码的耦合度

关键概念:

  • 数据抽象:只向外界提供必要的信息,而隐藏具体的实现细节
  • 接口:提供对对象进行操作的函数集合
  • 实现:接口的具体实现细节
  • 抽象类:包含至少一个纯虚函数的类
  • 访问修饰符:控制类成员的访问权限

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