• C++ 类之间的互相调用


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

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

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

    image

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

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

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

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

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

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

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

    为了简化起见

    在这里的类图如下

    image

    在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();
    
        }
    }

    运行结果

    image

    而在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

    image

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

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

    而这里你想要在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方法,有不会引起互相包含的问题了

    运行结果如下

    image

  • 相关阅读:
    网路连接出现意外错误
    linux install oracle jdk
    Chrome开发者工具详解(一)之使用断点来调试代码上
    jQuery对象与DOM对象的相互转换
    Velocity学习(二)之语法
    vscode学习(一)之vscode开发中绝对让你惊艳的插件!!!(个人在用) 持续更新。。。。
    css3新属性box-orient
    使用css控制文字显示几行并且剩余部分隐藏(移动端和PC端同样适用)
    移动端实现横滑
    移动端实1px细线方法
  • 原文地址:https://www.cnblogs.com/magicsoar/p/3776315.html
Copyright © 2020-2023  润新知