C++ 类之间的互相调用
这几天做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方法,有不会引起互相包含的问题了
运行结果如下
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Centos7安装ElasticSearch 6.4.1入门教程详解
- Windows 和 Linux 上Redis的安装守护进程配置方法
- 在Linux系统上安装Spring boot应用的教程详解
- 使用openssl 生成免费证书的方法步骤
- linux cd的含义以及用法
- leetcode栈之比较含退格的字符串
- CentOS使用本地yum源搭建LAMP环境图文教程
- 清除CentOS 6或CentOS 7上的磁盘空间的方法
- leetcode栈之二叉树的前序遍历
- 解决Linux下Mysql5.7忘记密码问题
- CentOS8.0 安装配置ftp服务器的实现方法
- Linux实现自动登录的实例讲解
- Linux中date命令转换日期提示date: illegal time format问题解决
- leetcode队列之最近的请求次数
- 安防视频云服务EasyCVR集成海康SDK时语音对出现杂音问题,如何解决?