跳转至

C++ OOP 面试高频知识点 - 02

封装思想,C++ 实现私有化成员 + get/set 接口

1. 封装的基本概念

封装(Encapsulation) 是面向对象编程的核心原则之一,它将数据(成员变量)和操作数据的方法(成员函数)结合在一起,形成一个独立的实体(对象),并对外部世界隐藏对象的内部实现细节。

封装的主要目的是: - 提高代码的可维护性 - 提高代码的安全性 - 简化编程接口

2. C++ 中的封装实现

在 C++ 中,我们通过访问控制关键字来实现封装,通常将成员变量设置为 privateprotected,并提供公共的 getset 接口来访问这些成员变量。

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

public:
    // 获取姓名
    string getName() const {
        return name;
    }

    // 设置姓名
    void setName(const string& newName) {
        name = newName;
    }

    // 获取年龄
    int getAge() const {
        return age;
    }

    // 设置年龄,添加范围验证
    void setAge(int newAge) {
        if (newAge >= 0 && newAge <= 150) {
            age = newAge;
        } else {
            cout << "Invalid age!" << endl;
        }
    }

    // 获取地址
    string getAddress() const {
        return address;
    }

    // 设置地址
    void setAddress(const string& newAddress) {
        address = newAddress;
    }
};

3. get 和 set 接口的设计原则

3.1 命名规范

  • get 方法通常以 get 开头,后跟成员变量名(首字母大写)
  • set 方法通常以 set 开头,后跟成员变量名(首字母大写)
  • 对于布尔值,get 方法也可以以 is 开头
class MyClass {
private:
    bool active;

public:
    bool isActive() const {
        return active;
    }

    void setActive(bool value) {
        active = value;
    }
};

3.2 访问修饰符

  • get 方法通常是 const 成员函数,表示不会修改对象状态
  • set 方法通常接受 const 引用参数,以避免不必要的拷贝
void setName(const string& newName) { // 使用 const 引用
    name = newName;
}

string getName() const { // const 成员函数
    return name;
}

3.3 验证和错误处理

set 方法中可以添加验证逻辑,确保成员变量的值在有效范围内:

void setAge(int newAge) {
    if (newAge >= 0 && newAge <= 150) {
        age = newAge;
    } else {
        throw invalid_argument("Age must be between 0 and 150");
    }
}

4. 封装的优势

4.1 信息隐藏

通过封装,我们可以隐藏类的内部实现细节,只暴露必要的接口给外部世界。

4.2 代码维护性

如果我们需要修改类的内部实现,只要保持公共接口不变,外部代码就不需要修改。

// 内部实现变更,但接口保持不变
void setAge(int newAge) {
    if (newAge >= 0 && newAge <= 120) { // 修改了年龄上限
        age = newAge;
    } else {
        throw invalid_argument("Age must be between 0 and 120");
    }
}

4.3 代码安全性

通过 set 方法的验证逻辑,我们可以确保成员变量的值始终是有效的。

5. 常见问题和回答

问题 1:为什么要将成员变量设置为 private?

将成员变量设置为 private 可以防止外部代码直接修改它们,从而避免了错误的修改和数据不一致性。

问题 2:什么时候应该使用 public 成员变量?

只有在变量是不可变的(const)或非常简单且安全的情况下,才应该使用 public 成员变量。

class Constants {
public:
    static const int MAX_VALUE = 100;
    static const double PI = 3.14159;
};

问题 3:封装会影响性能吗?

通常情况下,封装不会显著影响性能。现代编译器会优化简单的 getset 方法,使其与直接访问成员变量的性能几乎相同。


总结

封装是 C++ 面向对象编程的核心原则之一。通过将成员变量设置为 privateprotected,并提供公共的 getset 接口,我们可以提高代码的可维护性、安全性和复用性。


练习建议: 1. 设计一个 BankAccount 类,包含账户余额和交易记录 2. 实现存款和取款功能,并添加余额验证 3. 提供查询余额和交易记录的接口