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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM