简体   繁体   English

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

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

I'm trying to create a subject-observers system in C++, like the events system in C#.我正在尝试用 C++ 创建一个主题观察者系统,就像 C# 中的事件系统一样。 the observer class:观察者类:

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

the subject class:学科类:

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

the problem is when I try to implement addObserver I don't know how to add the reference to the set.问题是当我尝试实现addObserver我不知道如何将引用添加到集合中。

I understand make_shared<Observer<T>> is creating a new instance, so when I tried make_shared<Observer<T>>(observer) I got an error of trying to create an abstract class :我知道make_shared<Observer<T>>正在创建一个新实例,所以当我尝试make_shared<Observer<T>>(observer)我尝试创建一个抽象类时出错:

error: invalid new-expression of abstract class type 'Observer'错误:抽象类类型“观察者”的新表达式无效

I tried shared_ptr<Observer<T>> observerPtr(observer) and it did not work as well :我试过shared_ptr<Observer<T>> observerPtr(observer) ,但效果不佳:

error: no matching function for call to 'std::shared_ptr >::shared_ptr(Observer&)'错误:没有匹配的函数调用'std::shared_ptr >::shared_ptr(Observer&)'

how can I create a shared_ptr from a reference of an object derived from an abstract class?如何根据从抽象类派生的对象的引用创建shared_ptr

what I'm trying to achieve is make this example work:我想要实现的是让这个例子工作:

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
}

To answer your question regarding implementing addObserver, the easiest way to get it work is to store the pointer in the container:要回答有关实现 addObserver 的问题,使其工作的最简单方法是将指针存储在容器中:

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

Depending on how you wish to manage the life cycle of the observer object, you could use set<shared_ptr<Observer<T>>> , but in this case, you should pass the share_ptr<Observer<T>> as parameter of addObserver(shared_ptr<Observer<T>>& o) .根据您希望如何管理观察者对象的生命周期,您可以使用set<shared_ptr<Observer<T>>> ,但在这种情况下,您应该将share_ptr<Observer<T>>作为参数传递给addObserver(shared_ptr<Observer<T>>& o) If you have to use addObserver(Observer<T>&) interface and you want the "observers" set to co-manage the life cycle of the observer object, you could use std::enable_shared_from_this and make Observer a subclass of std::enable_shared_from_this.如果您必须使用addObserver(Observer<T>&)接口并且您希望“观察者”设置为共同管理观察者对象的生命周期,您可以使用 std::enable_shared_from_this 并使 Observer 成为 std:: 的子类enable_shared_from_this。

Hope this helps.希望这可以帮助。

how can I create a shared_ptr from a reference of an object derived from an abstract class?如何根据从抽象类派生的对象的引用创建 shared_ptr?

In general, you cannot.一般来说,你不能。 A shared pointer to abstract base can only be pointed to concrete instances.指向抽象基类的共享指针只能指向具体实例。 You generally cannot know the concrete type through a base reference at compile time.您通常无法在编译时通过基本引用知道具体类型。

You should probably change the interface so that the function accepts a shared pointer as argument, instead of a reference.您可能应该更改接口,以便函数接受共享指针作为参数,而不是引用。

how can I create a shared_ptr from a reference of an object derived from an abstract class?如何根据从抽象类派生的对象的引用创建 shared_ptr?

You cannot create a shared_ptr to an abstract class.您不能为抽象类创建 shared_ptr。

But you can do something to do the code work.但是你可以做一些事情来完成代码工作。

A possible solution is to define the base class Observer not abstrastct , removing the =0 .一个可能的解决方案是定义基类Observer而不是 abstrastct ,删除=0 Then for ensure you actual pure virtual function to not be called on base class Observer in the a bad way you can throw exception in the implementation of the method of the base class Observer.然后为了确保您不会在基类 Observer 上以一种糟糕的方式调用实际的纯虚函数,您可以在基类 Observer 的方法的实现中抛出异常。 So that when called on Observer class it raises an exception, in the other case ( for example in the AirConditioner class) it does its work without raising exception.因此,当在Observer类上调用时它会引发异常,在另一种情况下(例如在AirConditioner类中),它会在不引发异常的情况下完成其工作。

Note: This is a just a workaround for this case, try to re-think your code design for a better implementation注意:这只是这种情况的一种解决方法,请尝试重新考虑您的代码设计以获得更好的实现

C# makes it easy to ignore the lifetime of Observer in Subject , and things will (mostly) be ok. C#可以很容易忽略的寿命ObserverSubject ,事情会(主要)是好的。 C++ doesn't let you ignore lifetimes. C++ 不允许您忽略生命周期。

If a Subject should keep all the Observer s alive, then you need to pass std::shared_ptr<Observer> , not Observer & .如果Subject应该让所有Observer保持活动状态,那么您需要传递std::shared_ptr<Observer> ,而不是Observer &

If you are sure your Observer s always outlive your Subject , or can always call removeObserver before they die, then you can still pass Observer & , and store std::reference_wrapper<Observer> .如果您确定您的Observer总是比您的Subject removeObserver长,或者总是可以在它们死之前调用removeObserver ,那么您仍然可以传递Observer & ,并存储std::reference_wrapper<Observer>

If all your Observer s are owned by std::shared_ptr s, but you don't want Subject to affect their lifetime, pass and store std::weak_ptr<Observer> .如果您的所有Observer都归std::shared_ptr拥有,但您不希望Subject影响它们的生命周期,请传递并存储std::weak_ptr<Observer>

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

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