MST

星途 面试题库

面试题:C++纯虚函数在复杂设计模式中的应用及优化

在一个大型软件系统中,运用了观察者设计模式,其中涉及到多个主题(Subject)和观察者(Observer)。假设Subject类是一个包含纯虚函数的抽象类,用于定义通知观察者的接口。请详细阐述如何基于C++纯虚函数实现高效、可维护的观察者模式,包括如何处理动态添加和删除观察者、如何优化通知过程以避免性能瓶颈,以及在多线程环境下如何保证线程安全。同时,分析纯虚函数在这种复杂设计模式中的优势和潜在问题。
17.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 基于C++纯虚函数实现观察者模式

  1. 定义Subject类
#include <vector>
#include <memory>

class Observer;

class Subject {
public:
    virtual ~Subject() = default;
    // 纯虚函数,用于注册观察者
    virtual void attach(std::shared_ptr<Observer> observer) = 0;
    // 纯虚函数,用于移除观察者
    virtual void detach(std::shared_ptr<Observer> observer) = 0;
    // 纯虚函数,用于通知所有观察者
    virtual void notify() = 0;
};
  1. 定义Observer类
class Subject;

class Observer {
public:
    virtual ~Observer() = default;
    // 纯虚函数,用于接收通知
    virtual void update(const Subject& subject) = 0;
};
  1. 具体Subject类实现
class ConcreteSubject : public Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers;
public:
    void attach(std::shared_ptr<Observer> observer) override {
        observers.push_back(observer);
    }
    void detach(std::shared_ptr<Observer> observer) override {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }
    void notify() override {
        for (const auto& observer : observers) {
            observer->update(*this);
        }
    }
};
  1. 具体Observer类实现
class ConcreteObserver : public Observer {
public:
    void update(const Subject& subject) override {
        // 处理更新逻辑
    }
};

2. 处理动态添加和删除观察者

  • 添加观察者:在Subject类中定义attach纯虚函数,具体Subject类实现此函数,将观察者添加到观察者列表。例如上述ConcreteSubjectattach函数。
  • 删除观察者:在Subject类中定义detach纯虚函数,具体Subject类实现此函数,从观察者列表中移除指定观察者。如ConcreteSubjectdetach函数。

3. 优化通知过程以避免性能瓶颈

  • 批量通知:可以在Subject状态改变时,先记录改变,然后在合适时机(如事务结束)统一通知,减少频繁通知开销。
  • 减少不必要通知Subject内部记录状态变化标识,只有当状态真正变化时才通知观察者,避免无效通知。
  • 异步通知:使用多线程或异步队列,将通知任务放入队列,由专门线程处理,避免阻塞主线程。

4. 多线程环境下保证线程安全

  • 互斥锁:在Subject类中使用std::mutex保护观察者列表的修改和通知过程。例如在attachdetachnotify函数中加锁。
class ConcreteSubject : public Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers;
    std::mutex observerMutex;
public:
    void attach(std::shared_ptr<Observer> observer) override {
        std::lock_guard<std::mutex> lock(observerMutex);
        observers.push_back(observer);
    }
    void detach(std::shared_ptr<Observer> observer) override {
        std::lock_guard<std::mutex> lock(observerMutex);
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }
    void notify() override {
        std::lock_guard<std::mutex> lock(observerMutex);
        for (const auto& observer : observers) {
            observer->update(*this);
        }
    }
};
  • 读写锁:如果读操作(如notify)频繁,写操作(如attachdetach)较少,可以使用读写锁,读操作共享锁,写操作独占锁,提高并发性能。

5. 纯虚函数在这种复杂设计模式中的优势

  • 抽象接口定义:明确规定了SubjectObserver必须实现的接口,保证了不同实现类之间的一致性和规范性。
  • 多态性支持:使不同的SubjectObserver实现类能够通过统一接口交互,便于系统扩展和维护。
  • 解耦依赖SubjectObserver之间仅通过抽象接口依赖,降低了模块间耦合度。

6. 纯虚函数在这种复杂设计模式中的潜在问题

  • 增加实现复杂度:每个具体类都必须实现纯虚函数,对于复杂逻辑可能导致实现代码量增加。
  • 运行时错误风险:如果某个具体类没有正确实现纯虚函数,运行时会出现未定义行为,排查错误相对困难。
  • 内存管理问题:在使用智能指针管理SubjectObserver对象时,如果纯虚函数的实现涉及到内存操作,可能会引发内存泄漏或悬空指针问题。