2016-03-15 66 views
1

我正在嘗試爲我爲學校項目創建的遊戲實現觀察者模式。觀察者模式和繼承:不調用正確的功能

我創建了2個虛擬類Observer和Observable。

Observer.h:

Observer.cpp:

#include "stdafx.h" 
#include "Observer.h" 


Observer::Observer() 
{ 
} 

Observer::~Observer() 
{ 
} 

Observable.h:

#ifndef OBSERVEABLE_H 
#define OBSERVEABLE_H 
#include <vector> 
#include "Observer.h" 


class Observable 
{ 
    protected: 
    std::vector<Observer*> observers; 
    public: 
    Observable(); 
    virtual ~Observable(); 
    virtual void attach(Observer *a); 
    virtual void detach(Observer *a); 
    virtual void notify(); 
}; 

#endif 

Observable.cpp:

#include "stdafx.h" 
#include "Observable.h" 

Observable::Observable() 
{ 
} 

Observable::~Observable() 
{ 
} 

void Observable::attach(Observer *a) 
{ 
    observers.push_back(a); 
} 

void Observable::detach(Observer *a) 
{ 
    for (auto it = this->observers.begin(); it < this->observers.end(); it++) 
    { 

      if (*it == a) 
      { 
      this->observers.erase(it); 
      break; 
      } 
    } 
} 

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

我有一個地圖類,從可觀察繼承,並從觀察者繼承一個MapView類(地圖很長,我只包括了相關功能)

Map.h:

#ifndef MAP_H 
#define MAP_H 
#include "Observable.h" 
#include <iostream> 

class Map : public Observable 
{ 
    public: 
    Map(); 
    ~Map(); 
    void getLatest(); 
    void notify(); 
}; 

#endif 

地圖。 CPP:

#include "stdafx.h" 
#include "Map.h" 

Map::Map() 
{ 
} 

Map::~Map() 
{ 
} 

void Map::getLatest() 
{ 
    using namespace std; 
    cout << "This is the latest info!" << endl; 
} 

mapView.h:

#ifndef MAP_V_H 
#define MAP_V_H 
#include "Observer.h" 
#include "Map.h" 
#include "Plants.h" 

class mapView : public Observer 
{ 
    public: 
    mapView(); 
    ~mapView(); 
    void update(Map* map); 
}; 

#endif 

mapView.c PP:

#include "stdafx.h" 
#include "mapView.h" 
#include "Map.h" 

mapView::mapView() 
{ 
} 

mapView::~mapView() 
{ 
} 

void mapView::update(Map* map) 
{ 
    map->getLatest(); 
} 

最後,我主要只是創建了一個地圖和一個MapView,高度的MapView,並調用map.notify()

main.cpp中:

#include "stdafx.h" 
#include "setUp.h" 
#include "Map.h" 
#include "mapView.h" 

int main() 
{ 
    Map gameMap; 
    mapView view; 
    gameMap.attach(&view); 

    gameMap.notify(); 

    return 0; 
} 

我碰上這裏有很多問題。我無法創建mapView項目,因爲編譯器說我從未實現過更新(Observable * ob)的覆蓋版本....我嘗試更新(Map * map),但似乎儘管Map繼承自Observable,它似乎不算作相同的簽名,所以它不會編譯。

我試圖改變我的mapView :: update()函數來取代一個指向Observable的指針,但這不起作用,因爲函數調用了Map類中的某些東西。

然後我嘗試更改更新函數,使其不是虛擬函數(在虛擬類中爲空實現),但似乎任何時候我嘗試傳遞一個Map來更新,它將調用基類函數而不是mapView版本。換句話說,getLatest()永遠不會被調用。

我現在很困惑,因爲這種情況與我認爲多態性的工作方式不符。希望一些幫助或見解,如果可能的話!

謝謝

+0

模板是你的朋友在這裏 –

回答

2

你的基類聲明:

virtual void update(Observable* ob) =0; 

您派生類中聲明:

void update(Map* map); 

這些都不是相同的簽名。如果您使用了新的override關鍵字,那麼在編譯時您會發現實際上並沒有重寫虛擬方法。

如果您知道你將只能得到Map S,那麼你可以只使用static_cast。但是,它的安全使用dynamic_cast

void update(Observable* o) override { // now we're ok 
    if (auto map = dynamic_cast<Map*>(o)) { 
     // okay, got a Map 
     // .... 
    } 
    else { 
     // huh? 
    } 
} 

超簡式理論題外話。覆蓋的典型規則是參數類型中的co變體和contra變體。您可以指定更多派生的返回類型或更基礎的參數類型。這樣想一下 - 如果你有一個基類函數接受並返回Car* ......你的論點可以是Car*(這正是期望的),或者它可以是Vehicle*(因爲你可以用Vehicle做任何事情,你可以做一個Car - 這仍然有效),但它不能是一個SportsCar*(因爲呼叫者可能會傳遞給你一個Car這不是SportsCar,並有理由期待它的工作!)它沒有任何意義派生類只接受Map s - 您必須能夠接受任何Observable s,即使不是Map s!

+1

想強調'override'關鍵字有多偉大,你應該總是使用它,當工作瓦特/虛擬功能! –

+0

謝謝!這解決了我的問題。我曾經考慮過使用動態演員陣容,因爲我曾經看過,但我沒有正確使用它。你會說當你知道你期望派生類作爲參數傳遞時,這是覆蓋函數的標準方法嗎?比如說,當實現觀察者模式時。 – waffledave

+0

@waffledave我不知道「標準」,但這是一件非常合理的事情。 – Barry