这几天做C++11的线程池时遇到了一个问题,就是类A想要调用类B的方法,而类B也想调用类A的方法

这里为了简化起见,我用更容易理解的观察者模式向大家展开陈述

观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态时,依赖它的对象都会收到通知,并自动更新

观察者模式中有一个subject和observer

observer向subject注册成为一个观察者

当subject发生改变时,它通知所有的观察者

当一个observer不想作为观察者时,它会向subject发出请求,将自己从观察者中除名

注意,在这里是存在一个互相调用的

subject肯定需要知道observer的方法,这样它才能在状态发生改变时调用observer的方法通知他们

而当一个observer想要将自己从观察者中除名的时候,它需要保留一个subjet的引用,并让subject调用remove方法将自己除名

为了简化起见

在这里的类图如下

在java,我们可以这样实现

import java.util.ArrayList;
class Subject { public void change() { for (Observer x :observerList) {
x.Show();
}
} public void register(Observer o) {
observerList.add(o);
} public void Remove(Observer o) {
observerList.remove(o);
} private ArrayList<Observer> observerList=new ArrayList<Observer>();
} class Observer {
public void Show() {
System.out.println("I konw The Subject is changed");
} public Observer(Subject s) {
subject = s;
} public void Remove() {
subject.Remove(this);
} private Subject subject;
} public class Observertry { public static void main(String[] args) {
Subject s = new Subject();
Observer o = new Observer(s);
s.register(o);
s.change(); }
}

运行结果

而在C++中

如果我们在main.cpp中编写出以下代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Observer;
class Subject;
class Observer
{
public: Observer(Subject *s)
{
subject = s;
}
void Remove(Subject *s)
{
s->Remove(this);
}
void Show()
{
cout << "I konw Subject is change" << endl;
}
private:
Subject *subject;
};
class Subject
{
public:
void change()
{
for (vector<Observer*>::iterator it = observerlist.begin(); it != observerlist.end(); it++)
{
(*it)->Show();
} }
void Remove(Observer *o)
{
observerlist.erase(find(observerlist.begin(), observerlist.end(), o));
}
void Register(Observer *o)
{
observerlist.push_back(o);
}
private:
vector<Observer*> observerlist; };
int main()
{
Subject s;
Observer o(&s);
s.Register(&o);
s.change();
system("pause");
}

会发现这段代码无法编译通过

在vs2013中会有以下error

这是因为虽然有类的成员的前向声明

但你仅可以定义指向这种裂隙的指针或引用,可以声明但不能定义以这种不完全类型或者返回类型的参数

而这里你想要在Observer类里调用subject的方法,而subject是在Observer的后面声明定义的,所以无法调用subject的方法

而C++是没有对类的函数的前向声明的

所以我们要有一个方法,让我们在声明类Subject时能看到类Observer的声明

而在声明类Observer时,能看到类Subject的声明

所以我们想到将Subject和Observer分别放到两个文件中去

所以我们有了如下尝试

subject.h

#pragma once
#include "Observer.h"
#include <iostream>
#include <vector> class Subject
{
public:
void change();
void Remove(Observer *o);
void Register(Observer *o);
std::vector<Observer*> observerlist;
};

observer.h

#pragma once
#include <iostream>
#include "Subject.h"
using namespace std;
class Subject; class Observer
{
public:
Observer(Subject *s); void Remove(Subject *s);
void Show();
Subject *subject;
};

但这一次依旧无法通过编译

因为我们这里出现了头文件的互相包含

subject.h中包含了observer.h

observer.h中包含了subject.h

所以正确的方法是把其中的一个的include放到相应的实现文件中即cpp文件中

代码如下

subject.h

#pragma once
#include "Observer.h"
#include <iostream>
#include <vector> class Subject
{
public:
void change();
void Remove(Observer *o);
void Register(Observer *o);
std::vector<Observer*> observerlist;
};

subject.cpp

#include "Subject.h"

void Subject::change()
{
for (vector<Observer*>::iterator it = observerlist.begin(); it != observerlist.end(); it++)
{
(*it)->Show();
}
} void Subject::Remove(Observer *o)
{
observerlist.erase(find(observerlist.begin(), observerlist.end(), o));
}
void Subject::Register(Observer *o)
{
observerlist.push_back(o);
}

observer.h

#pragma once
#include <iostream> using namespace std;
class Subject; class Observer
{
public:
Observer(Subject *s); void Remove(Subject *s);
void Show();
Subject *subject;
};

observer.cpp

#include "Observer.h"
#include "Subject.h" Observer::Observer(Subject *s)
{
subject = s;
} void Observer::Remove(Subject *s)
{
s->Remove(this);
}
void Observer::Show()
{
cout << "I know Subject is changed" << endl;
}

我们将#include “Subject.h”放到了observer.cpp中

这样就在observer的实现中就可以看到Subject的声明,进而调用subject的Remove方法,有不会引起互相包含的问题了

运行结果如下

C++ 类之间的互相调用的更多相关文章

  1. Java 类与类之间的调用

    方法1. 新建一个类. 然后在调用类中先进行被调用类实例化,然后通过实例化的对象访问. 例如: //先定义一个类 import static java.lang.System.out; public ...

  2. (转) C++中基类和派生类之间的同名函数的重载问题

    下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...

  3. JAVA和C/C++之间的相互调用。

    在一些Android应用的开发中,需要通过JNI和 Android NDK工具实现JAVA和C/C++之间的相互调用. Java Native Interface (JNI)标准是java平台的一部分 ...

  4. 图解UML类与类之间的六中关系

    大话设计模式上的一个图,我用EA画出来的:  UML中的6大关系相关英文及音标:  依赖关系 dependency [di'pendənsi]  关联关系 association  [ə,səuʃi' ...

  5. Java类之间的关联关系(转载)

    Java类之间的关联关系 UML类图中的关系分为四种:泛化.依赖.关联.实现:关联关系又可以细化为聚合和组合. 一.泛化(Generalization) 泛化是父类和子类之间的关系,子类继承父类的所有 ...

  6. oc之封装与类之间的关系

    1. 面向对象的特征-封装? 封装: 现实生活中的封装: 将很多的小东西 塞在1个大口袋里面. 好处: a. 对外部屏蔽. b. 方便管理. 代码的封装: 函数/方法 就是1种封装的体现: 将一段代码 ...

  7. java 类与类之间的关系 及uml图

    类与接口之间的关系 : 继承 类与类之间的关系 :继承关系  包含关系 类与对象之间的关系 : 实例 UML 类图中类与类之间的关系: 泛化关系(generalization) 关联关系(associ ...

  8. 全面解释java中StringBuilder、StringBuffer、String类之间的关系

    StringBuilder.StringBuffer.String类之间的关系 java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,在上一篇博文中我 ...

  9. 【47】java的类之间的关系:泛化、依赖、关联、实现、聚合、组合

    java的类之间的关系:泛化.依赖.关联.实现.聚合.组合 泛化: • 泛化关系(Generalization)也就是继承关系,也称为"is-a-kind-of"关系,泛化关系用于 ...

随机推荐

  1. Asp调用存储过程,command.CreateParameter 参数值的类型说明

    Asp调用存储过程,command.CreateParameter 参数值的类型说明 Asp调用各种存储过程,包括带参数,无参数,输入输出参数,带返回值等. 1,调用没有参数的存储过程 <% s ...

  2. 2017-2018-1 20155214 《信息安全系统设计基础》 第9周课下测试-mypwd

    2017-2018-1 20155214 <信息安全系统设计基础> 第9周课下测试-mypwd(深入版) 题目要求: 1 学习pwd命令 2 研究pwd实现需要的系统调用(man -k; ...

  3. JAVA Swing开发单机版项目

    一.序 最近公司做的项目里出现了一个新的需求,项目大部分是为金融业定制开发的数据集成平台,包括数据的采集,处理,使用. 数据的采集方式不固定,有机构化数据,有非结构话数据,还有附件等其它文件形式. 对 ...

  4. 北京Uber优步司机奖励政策(4月21日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. python线程的使用模式

    为了解决阻塞(如I/O)问题,我们需要对程序进行并发设计. 本文将通过将线程和队列 结合在一起,轻松地在 Python 中完成线程编程,创建一些简单但有效的线程使用模式. 一.使用线程 先看一个线程不 ...

  6. 3992: [SDOI2015]序列统计

    3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...

  7. P4360 [CEOI2004]锯木厂选址

    P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...

  8. [BZOJ3167][HEOI2013]SAO[树dp+组合数学]

    题意 给定 \(n\) 个节点和 \(n-1\) 个限制,每个节点有一个权值,每个限制形如:\(a_i< a_j\) ,问有多少个 \(1\) 到 \(n\) 排列满足要求. \(n\leq 1 ...

  9. spark日志配置及问题排查方式。

    此文已由作者岳猛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 任何时候日志都是定位问题的关键,spark也不会例外,合适的配置和获取spark的driver,am,及exe ...

  10. VRRP+tunnel+IP SLA+Track实现冗余切换

    IP SLA(Internet Protocol Service-Level Agreement)互联网服务等级协议,本实验里通过发送测试报文,测试下一跳是否可达,结合Track实现冗余静态路由的切换 ...