You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用观察者模式多次继承Subject时误用观察者列表问题

问题分析与解决方案

你的核心问题出在两个地方:一是Observer类的notify方法访问权限导致的编译错误(进而引发运行时未定义行为);二是需要确保多重继承的不同Subject<T>特化类各自独立维护观察者列表,避免调用混淆。


1. 修复Observer的notify访问权限

Subject的notify方法需要调用Observer的同名方法,但你当前将Observer::notify设为private,这会导致编译失败,后续的段错误大概率是由此引发的未定义行为。有两种修复方式:

方式A:将notify改为public

直接开放访问权限,最简单直接:

template<typename T>
class Observer {
public:
    virtual void notify(const T& data) = 0;
    virtual ~Observer() = default;
};

方式B:声明Subject为友元

如果希望保持notify的私有性,可通过友元授权Subject<T>访问:

template<typename T>
class Observer {
private:
    virtual void notify(const T& data) = 0;
    friend class Subject<T>; // 允许Subject<T>调用notify
public:
    virtual ~Observer() = default;
};

2. 确保notify调用的基类唯一性

你在Car类中使用this->Subject<MoveData>::notify(moveData)的写法是正确的,这种显式限定能保证调用的是对应特化基类的notify方法,访问的也是该基类独立维护的observers列表。

如果省略基类限定(直接写notify(moveData)),会因两个基类都有notify方法而产生编译二义性,务必避免这种写法。


3. 优化建议:封装订阅接口

为了避免外部调用Car的subscribe方法时出现二义性(两个基类都有该方法),可以在Car类中封装针对不同事件的订阅方法:

// 假设已定义事件数据结构
struct MoveData {};
struct SteerData {};

class Car : public Subject<MoveData>, public Subject<SteerData> {
public:
    // 封装Move事件的订阅
    void subscribeMove(Observer<MoveData>* observer) {
        Subject<MoveData>::subscribe(observer);
    }

    // 封装Steer事件的订阅
    void subscribeSteer(Observer<SteerData>* observer) {
        Subject<SteerData>::subscribe(observer);
    }

    void move() {
        const MoveData moveData{};
        Subject<MoveData>::notify(moveData);
    }

    void steer() {
        const SteerData steerData{};
        Subject<SteerData>::notify(steerData);
    }
};

验证示例

创建具体观察者类测试:

#include <iostream>
#include <list>

// 此处省略Observer和Subject的修复代码,使用上述方式A或B

class MoveObserver : public Observer<MoveData> {
public:
    void notify(const MoveData& data) override {
        std::cout << "收到Move事件\n";
    }
};

class SteerObserver : public Observer<SteerData> {
public:
    void notify(const SteerData& data) override {
        std::cout << "收到Steer事件\n";
    }
};

int main() {
    Car myCar;
    MoveObserver moveObs;
    SteerObserver steerObs;

    myCar.subscribeMove(&moveObs);
    myCar.subscribeSteer(&steerObs);

    myCar.move(); // 仅触发MoveObserver的notify
    myCar.steer(); // 仅触发SteerObserver的notify

    return 0;
}

运行后会分别输出对应事件的通知,确保两个事件的观察者列表完全独立。

内容的提问来源于stack exchange,提问作者Placeblock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:40:18