簡體   English   中英

C++ 運行時多態與模板

[英]C++ runtime polymorphism with templates

我的程序有可觀察者和觀察者。 這是可觀察的。

template <typename E>
class Observable {
  private:
    std::list<E> observers;

  public:
    void addObserver(E observer) {
        observers.push_back(observer);
    }

    void notifyAll() {
        for (auto & observer: observers) {
            observer.doSomething();
        }
    }
};

有一個基礎AnimalObserver和派生的觀察者CatObserverDogObserver AnimalObserver有一個虛方法, void doSomething() CatObserverDogObserver實現了這個方法。

class DogObserver : public AnimalObserver {

  public:
    DogObserver() = default;
    void doSomething() const {
        std::cout << "woof!";
    }
};
class CatObserver : public AnimalObserver {

  public:
    CatObserver() = default;
    void doSomething() const {
        std::cout << "meow!";
    }
};

我創建我的 Observable 並像這樣運行我的程序:

auto observable = Observable<AnimalObserver>();
auto cat = CatObserver();
auto dog = DogObserver();

observable.register(cat);
observable.register(dog);

observable.notifyAll();

發生的情況是AnimalObserver的 doSomething 方法被調用了兩次,而不是CatObserverDogObserver doSomething 方法被調用。 我想調用派生類的doSomething方法,而不是父類。

我想做的是保留一個來自AnimalObserver的不同觀察者的列表,並調用他們的doSomething行為而不是虛擬 function。

如果以前有人問過這個問題,我深表歉意,但我什至不確定要搜索什么。 我正在閱讀有關模板的信息,但迷路了。

唯一的問題是:您必須在 Observable class 中存儲指向基礎 class AnimalObserver 的指針。 您可以通過多種方式做到這一點。 unique_ptr<> 浮現在腦海中。

這是一個帶有一些提示的實現。 天螺栓: https://godbolt.org/z/1Gq35G

#include <list>
#include <iostream>
#include <memory>
using namespace std;

struct AnimalObserver
{
    virtual ~AnimalObserver() { }
    // Hint 1: Declare abstract so that it won't even compile if you use the 
    //  base class directly in a collection - i.e. and not a pointer to the base.
    virtual void doSomething() const = 0;
};

template <typename E>
class Observable {
  private:
    typedef unique_ptr< E > _TyPtrContained;
    std::list<_TyPtrContained> observers;

  public:
    void addObserver( unique_ptr< E > && rrobserver ) {
        // Remember that inside a method that receives a rvalue-reference, 
        //  it is an lvalue-reference and must be std::move()'d when passing to a 
        //  method that accepts an rvalue-reference.
        observers.push_back( std::move( rrobserver ) );
    }

    void notifyAll() {
        for (auto & observer: observers) {
            observer->doSomething();
        }
    }
};

class DogObserver : public AnimalObserver {
  public:
    DogObserver() = default;
    // Hint 2: Use override to ensure that you are overriding an actual 
    //  virtual and not just declaring a method with a different signature 
    //  than the base.
    void doSomething() const override {
        std::cout << "woof!";
    }
};

class CatObserver : public AnimalObserver {
  public:
    CatObserver() = default;
    void doSomething() const override {
        std::cout << "meow!";
    }
};

int
main()
{
    auto observable = Observable<AnimalObserver>();
    // Hint 3: You can assign a unique_ptr<derived> to a unique_ptr<base>.
    unique_ptr< AnimalObserver > cat = make_unique< CatObserver >();
    unique_ptr< AnimalObserver > dog = make_unique< DogObserver >();

    // We move the local unique_ptrs into the addObserver method so that
    //  they are then moved into the list using the rvalue-reference version
    //  of list<>::push_back().
    observable.addObserver( std::move( cat ) );
    observable.addObserver( std::move( dog ) );

    observable.notifyAll();
    // And, voila, things work...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM