观察者模式和继承:没有调用正确的函数

时间:2016-03-15 01:28:25

标签: c++ inheritance observer-pattern

我正在尝试为我正在为学校项目创建的游戏实施Observer模式。

我创建了2个虚拟类,Observer和Observable。

Observer.h:

#ifndef OBSERVER_H
#define OBSERVER_H
#include <vector>

class Observable;

class Observer
{
    public:
     Observer();
     virtual ~Observer();
     virtual void update(Observable* ob) =0;
};

#endif

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

我有一个继承自Observable的Map类,以及一个继承自Observer的mapView类(Map非常长,我只包含了相关的函数)

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

Map.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.cpp:

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

mapView::mapView()
{
}

mapView::~mapView()
{
}

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

最后,我的主要创建一个Map和一个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)....我尝试使用update(Map * map)但看起来尽管Map继承自Observable,但它似乎并不算作相同的签名,所以它不会编译。

我试图改变我的mapView :: update()函数来取代一个指向Observable的指针,但这不起作用,因为该函数从Map类调用了一些东西。

然后我尝试将更新函数更改为不是虚函数(在虚拟类中使用空实现),但似乎每当我尝试传递Map进行更新时,它都会调用基类函数而不是mapView版本。换句话说,getLatest()永远不会被调用。

我现在很困惑,因为这与我认为多态性的工作方式不符。如果可能的话,会感激一些帮助或见解!

谢谢,

1 个答案:

答案 0 :(得分:2)

您的基类声明:

virtual void update(Observable* ob) =0;

你派生的类声明:

void update(Map* map);

这些签名不一样。如果你使用了新的override关键字,你会在编译时看到你实际上没有覆盖虚方法。

如果您知道,您只会获得Map,那么您可以使用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 <​​/ em>变体和参数类型中的 contra 变体。您可以指定更多派生的返回类型或更多基础的参数类型。以这种方式思考 - 如果你有一个基类函数并且返回Car* ...你的参数可以是Car*(这正是预期的那样),或者它可以是{{1 (因为您可以使用Vehicle*执行任何操作,您可以使用Vehicle - 这仍然有效),但它不能是Car(因为调用者可能会通过)你是一个不是SportsCar*的{​​{1}},并且有理由期望这个有用!)派生类只接受Car s是没有意义的 - 你必须能够接受任何SportsCar,甚至不是Map s!