c++总复习

发布于:2024-12-18 ⋅ 阅读:(117) ⋅ 点赞:(0)
  1. C++ 中面向对象编程实现数据隐藏的方式
    • 访问控制修饰符
      • private 关键字:将类的成员(数据成员和成员函数)声明为private,这些成员只能在类的内部被访问。例如,有一个BankAccount类,账户余额balance是敏感信息,应该隐藏起来。
class BankAccount {
private:
    double balance;
public:
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    void withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
        }
    }
    double getBalance() {
        return balance;
    }
};
  • 原理和优势:在这个例子中,balance被声明为private。外部代码不能直接访问balance,只能通过depositwithdrawgetBalance这些公共成员函数来间接操作和获取账户余额。这样就可以在这些函数中添加各种验证逻辑,比如存款金额不能为负数、取款金额不能超过余额等,保证数据的完整性和安全性。
  • protected 关键字(用于继承场景):在有继承关系的类层次结构中,protected成员可以在派生类中访问,但对于外部类来说是不可见的。例如,有一个基类Shape和派生类Circle
class Shape {
protected:
    int color;
public:
    Shape(int c) : color(c) {}
};
class Circle : public Shape {
public:
    Circle(int c) : Shape(c) {}
    void printColor() {
        std::cout << "Color of the circle: " << color << std::endl;
    }
};
  • 原理和优势:在Shape类中,color被声明为protected。它不能被外部代码直接访问,但在派生类Circle中可以访问。这种机制允许在继承层次结构中,基类将一些成员开放给派生类,让派生类能够在一定程度上共享基类的内部状态,同时又限制了外部对这些成员的访问。
  • 信息隐藏的设计理念:除了使用访问控制修饰符,在设计类时,应该遵循信息隐藏的原则。只暴露必要的接口给外部,隐藏类的内部实现细节。例如,对于一个Stack类,用户只需要知道pushpoptop等操作接口,而不需要了解栈是用数组还是链表实现的。
class Stack {
private:
    std::vector<int> data;
public:
    void push(int value) {
        data.push_back(value);
    }
    int pop() {
        if (!data.empty()) {
            int topValue = data.back();
            data.pop_back();
            return topValue;
        }
        throw std::runtime_error("Stack is empty");
    }
    int top() {
        if (!data.empty()) {
            return data.back();
        }
        throw std::runtime_error("Stack is empty");
    }
};
  • 原理和优势:这里Stack类内部使用std::vector来存储数据,这是实现细节。外部用户只通过pushpoptop接口来使用栈,即使将来修改Stack的内部存储结构(比如改为链表),只要接口保持不变,使用Stack的其他代码不需要修改。
  1. C++ 中面向对象编程处理异常的方法
    • try - catch 块
      • 基本语法和流程try块中放置可能抛出异常的代码,catch块用于捕获并处理异常。例如,在一个除法运算函数中,除数不能为零。
double divide(double dividend, double divisor) {
    try {
        if (divisor == 0) {
            throw std::runtime_error("Divisor cannot be zero");
        }
        return dividend / divisor;
    } catch (const std::runtime_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 0;
    }
}
  • 原理和优势:当divisor为 0 时,会抛出一个std::runtime_error类型的异常。程序流程会立即跳转到catch块,catch块捕获到这个异常后,可以进行相应的错误处理,比如打印错误信息并返回一个默认值。这样可以避免程序因为异常而崩溃,使程序更加健壮。
  • 异常类型层次结构:C++ 标准库有一个异常类型层次结构,std::exception是所有标准异常的基类。派生类包括std::runtime_errorstd::logic_error等。可以根据不同的异常类型进行不同的处理。例如,有一个函数可能抛出两种不同类型的异常。
void someFunction() {
    try {
        // 可能抛出std::runtime_error或std::logic_error的代码
    } catch (const std::runtime_error& e) {
        std::cerr << "Runtime error: " << e.what() << std::endl;
    } catch (const std::logic_error& e) {
        std::cerr << "Logic error: " << e.what() << std::endl;
    }
}
  • 原理和优势:通过这种方式,可以针对不同类型的异常进行精细的处理。比如,对于runtime_error可能是由于运行时环境问题(如文件不存在、网络连接中断等),而logic_error可能是程序逻辑错误(如参数无效等),可以分别采取不同的恢复策略或者错误提示。
  • 自定义异常类:除了使用标准异常类,还可以自定义异常类来更好地适应具体的应用场景。例如,在一个学生成绩管理系统中,定义一个InvalidGradeException
class InvalidGradeException : public std::runtime_error {
public:
    InvalidGradeException(const std::string& message) : std::runtime_error(message) {}
};
class StudentGrades {
public:
    void setGrade(int grade) {
        if (grade < 0 || grade > 100) {
            throw InvalidGradeException("Grade must be between 0 and 100");
        }
        // 设置成绩的代码
    }
};
  • 原理和优势:当setGrade函数接收到无效的成绩时,会抛出InvalidGradeException。这种自定义异常类可以携带更具体的错误信息,并且可以在catch块中根据自定义异常类型进行专门的处理,使得异常处理更加贴合实际业务逻辑。同时,继承自std::runtime_error(或其他标准异常基类)可以利用标准库的异常处理机制,如what()函数来获取错误信息。

网站公告

今日签到

点亮在社区的每一天
去签到