繁体   English   中英

如何创建shared_ptr的容器到抽象类

[英]how to create a container of shared_ptr to abstract class

我正在尝试用 C++ 创建一个主题观察者系统,就像 C# 中的事件系统一样。 观察者类:

template <class T>
class Observer {
    int id;
public:
    static int nextId;
    Observer() : id(nextId++) {}
    virtual void handleEvent(const T&) = 0;
    virtual ~Observer();
};

学科类:

template<class T>
class Subject {
    set<shared_ptr<Observer<T>>> observers;
public:
    Subject() : observers() {}
    void notify(const T&);
    void addObserver(Observer<T>& );
    void removeObserver(Observer<T>&);
    Subject<T>& operator+=(Observer<T>&);
    Subject<T>& operator-=(Observer<T>&);
    Subject<T>& operator()(const T&);
};

问题是当我尝试实现addObserver我不知道如何将引用添加到集合中。

我知道make_shared<Observer<T>>正在创建一个新实例,所以当我尝试make_shared<Observer<T>>(observer)我尝试创建一个抽象类时出错:

错误:抽象类类型“观察者”的新表达式无效

我试过shared_ptr<Observer<T>> observerPtr(observer) ,但效果不佳:

错误:没有匹配的函数调用'std::shared_ptr >::shared_ptr(Observer&)'

如何根据从抽象类派生的对象的引用创建shared_ptr

我想要实现的是让这个例子工作:

class TemperatureSensor : public Subject<int> {};

class AirConditioner : public Observer<int> {

    static int nextId;
    int id;

    void onTemperatureChange(int temperature){
        std::cout << "Air Conditioner #" << id << " got a report from TemperatureSensor, reading " << temperature << std::endl;
    }

public:
    AirConditioner() : Observer() {
        id = (++nextId);
    }

    void handleEvent(const int& param) override {
        onTemperatureChange(param);
    }
};
int AirConditioner::nextId = 0;

int main(){
    TemperatureSensor s;
    AirConditioner a,b,c;

    (((s += a) += b) += c);

    s(42);  // Should print:
            // Air Conditioner #1 got a report from TemperatureSensor, reading 42
            // Air Conditioner #2 got a report from TemperatureSensor, reading 42
            // Air Conditioner #3 got a report from TemperatureSensor, reading 42
}

要回答有关实现 addObserver 的问题,使其工作的最简单方法是将指针存储在容器中:

template<class T>
class Subject {
    set<Observer<T>*> observers;
public:
    Subject() : observers() {}
    void addObserver(Observer<T>& o) { observers.insert(&o); }

根据您希望如何管理观察者对象的生命周期,您可以使用set<shared_ptr<Observer<T>>> ,但在这种情况下,您应该将share_ptr<Observer<T>>作为参数传递给addObserver(shared_ptr<Observer<T>>& o) 如果您必须使用addObserver(Observer<T>&)接口并且您希望“观察者”设置为共同管理观察者对象的生命周期,您可以使用 std::enable_shared_from_this 并使 Observer 成为 std:: 的子类enable_shared_from_this。

希望这可以帮助。

如何根据从抽象类派生的对象的引用创建 shared_ptr?

一般来说,你不能。 指向抽象基类的共享指针只能指向具体实例。 您通常无法在编译时通过基本引用知道具体类型。

您可能应该更改接口,以便函数接受共享指针作为参数,而不是引用。

如何根据从抽象类派生的对象的引用创建 shared_ptr?

您不能为抽象类创建 shared_ptr。

但是你可以做一些事情来完成代码工作。

一个可能的解决方案是定义基类Observer而不是 abstrastct ,删除=0 然后为了确保您不会在基类 Observer 上以一种糟糕的方式调用实际的纯虚函数,您可以在基类 Observer 的方法的实现中抛出异常。 因此,当在Observer类上调用时它会引发异常,在另一种情况下(例如在AirConditioner类中),它会在不引发异常的情况下完成其工作。

注意:这只是这种情况的一种解决方法,请尝试重新考虑您的代码设计以获得更好的实现

C#可以很容易忽略的寿命ObserverSubject ,事情会(主要)是好的。 C++ 不允许您忽略生命周期。

如果Subject应该让所有Observer保持活动状态,那么您需要传递std::shared_ptr<Observer> ,而不是Observer &

如果您确定您的Observer总是比您的Subject removeObserver长,或者总是可以在它们死之前调用removeObserver ,那么您仍然可以传递Observer & ,并存储std::reference_wrapper<Observer>

如果您的所有Observer都归std::shared_ptr拥有,但您不希望Subject影响它们的生命周期,请传递并存储std::weak_ptr<Observer>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM