You need to enable JavaScript to run this app. C++实现Observer设计模式遇未声明标识符等编译错误求助
优惠活动
大模型
产品
解决方案
定价
更多

C++实现Observer设计模式遇未声明标识符等编译错误求助

问题根因

所有编译错误的核心是头文件循环包含,无其他隐藏问题。
两个头文件互相#include对方,在#pragma once的保护下,会导致编译器加载类型定义时出现“半截加载”的连锁问题:

  • 编译Obs.h时第一行就跳转加载Subject.h
  • 加载Subject.h时第一行又跳转加载Obs.h,此时Obs.h因#pragma once被判定为已加载,直接跳过
  • 等编译Subject.h到需要用到Observer类型的位置时,Observer的完整定义根本还没加载到(Obs.h才刚被打开就跳走了)
  • 切回Obs.h继续编译时,遇到需要用到Subject类型的位置,Subject的完整定义也没加载到(Subject.h才刚被打开就跳回Obs.h了)
    最终就会报出一堆“标识符未声明”“缺少类型说明符”“语法错误缺分号”的连锁报错,和你贴的所有错误信息完全对应。
    另外还有两个衍生小问题:
  • 类的成员函数实现如果要调用对方类的方法,需要拿到对方类的完整定义,不能直接写在头文件里,不然就算拆了循环包含,还是会因为前置声明的类型不完整报错
  • 部分头文件里只用到Subject的指针,之前靠循环传递包含拿到Subject的定义,等循环依赖拆了之后会出现新的未声明错误
分步修正方案

1. 重写Obs.h,替换循环包含为前置声明

Observer类的成员、构造函数参数都只用到Subject的指针,不需要拿到Subject的完整定义,直接删掉头文件里的#include "Subject.h",换前置声明;同时把构造函数的实现移到独立的cpp文件里(因为构造函数内部要调用Subject的attach()方法,需要完整定义)
修改后的Obs.h:

#pragma once
// 前置声明,替代原来的#include "Subject.h"
class Subject;

class Observer
{
    Subject* model;
public:
    Observer(Subject* mod);
    virtual void update() = 0;
};

新增Obs.cpp文件,放置Observer构造函数的实现:

#include "Obs.h"
#include "Subject.h"

Observer::Observer(Subject* mod) {
    model = mod;
    model->attach(this);
}

2. 重写Subject.h,去掉循环包含

Subject类只存储Observer的指针,不需要Observer的完整定义,直接删掉头文件里的#include "Obs.h",保留vector参数里的内置前置声明;同时把notify()函数的实现移到独立的cpp文件里(因为notify()内部要调用Observer的update()方法,需要完整定义)
修改后的Subject.h:

#pragma once
#include <vector>
// 删除原来的#include "Obs.h"
class Subject
{
    // 这里的class Observer就是内置前置声明,不需要额外包含头文件
    std::vector <class Observer*> views;
public:
    void attach(Observer *obs) {
        views.push_back(obs);
    }
    void notify();
};

新增Subject.cpp文件,放置notify函数的实现:

#include "Subject.h"
#include "Obs.h"

void Subject::notify() {
    for (int i = 0; i < views.size(); i++) {
        views[i]->update();
    }
}

3. 补全其他头文件的前置声明

原来的Class.h、Class1.h里都只用到Subject*类型的指针参数,之前靠Obs.h里的传递包含拿到Subject的定义,现在循环包含拆了之后,要自己加前置声明,避免新的未声明错误。
修改后的Class.h:

#pragma once
#include "Obs.h"
// 新增前置声明
class Subject;

class Class : public Observer
{
    int n1, n2;
public:
    Class(Subject* sub);
    void setNumbers(int, int);
    int sum();
    void update();
};

对应修改Class.cpp的头文件包含,加上#include "Subject.h",其余类实现保持不变:

#include "Class.h"
#include "Subject.h"
#include <iostream>
// 原有实现代码无需修改

同样修改Class1.h:

#pragma once
#include "Obs.h"
#include "Class.h"
// 新增前置声明
class Subject;

class Class1: public Observer
{
    int result;
    Class c1, c2;
public:
    Class1(Subject* sub);
    void setNumbers(Class, Class);
    int multiply();
    void update();
};

对应修改Class1.cpp的头文件包含,加上#include "Subject.h",其余类实现保持不变:

#include "Class1.h"
#include "Subject.h"
#include <iostream>
// 原有实现代码无需修改

4. 修正逻辑小问题

原Test.cpp中计算乘积的输出写错了,把直接输出c1.sum()改成调用cl1.multiply()即可:

// 原来的错误代码
// std::cout << "(1 + 3) x (4 + 6) =  " << c1.sum() << std::endl;
// 修正为
std::cout << "(1 + 3) x (4 + 6) =  " << cl1.multiply() << std::endl;

内容的提问来源于stack exchange,提问作者Sıla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 21:36:03