如何创建 shared_ptr 的容器来抽象 class
how to create a container of shared_ptr to abstract class
我正在尝试用 C++ 创建一个主题-观察者系统,就像 C# 中的事件系统一样。
观察者 class:
template <class T>
class Observer {
int id;
public:
static int nextId;
Observer() : id(nextId++) {}
virtual void handleEvent(const T&) = 0;
virtual ~Observer();
};
主题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&);
};
问题是当我尝试实现时 addObserver
我不知道如何将引用添加到集合中。
我知道 make_shared<Observer<T>>
正在创建一个新实例,所以当我尝试 make_shared<Observer<T>>(observer)
时,我在尝试创建抽象时遇到错误 class :
error: invalid new-expression of abstract class type ‘Observer’
我试过 shared_ptr<Observer<T>> observerPtr(observer)
但效果不佳:
error: no matching function for call to ‘std::shared_ptr >::shared_ptr(Observer&)’
如何从派生自抽象 class 的对象的引用创建 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
}
how can I create a shared_ptr from a reference of an object derived from an abstract class?
一般来说,你不能。指向抽象基的共享指针只能指向具体实例。您通常无法在编译时通过基引用知道具体类型。
您可能应该更改接口,以便函数接受共享指针而不是引用作为参数。
如何从派生自抽象 class 的对象的引用创建 shared_ptr?
You cannot create a shared_ptr to an abstract class.
但是您可以做一些事情来完成代码工作。
一个可能的解决方案是定义base class Observer not abstrastct,删除 =0
。然后为了确保您实际的纯虚函数不会以一种不好的方式在 base class Observer 上调用,您可以在 base class Observer 的方法的实现中抛出异常。因此,当在 Observer class 上调用时,它会引发异常,在另一种情况下(例如在 AirConditioner class) 它会在不引发异常的情况下完成工作。
注意:这只是这种情况的一种解决方法,请尝试重新考虑您的代码设计以获得更好的实现
要回答有关实现 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>>
作为 [=13= 的参数传递].如果你必须使用 addObserver(Observer<T>&)
接口并且你希望 "observers" 集共同管理观察者对象的生命周期,你可以使用 std::enable_shared_from_this 并使 Observer 成为 [=22] 的子类=].
希望对您有所帮助。
C# 可以很容易地忽略 Subject
中 Observer
的生命周期,并且事情(大部分)会没问题。 C++ 不允许您忽略生命周期。
如果 Subject
应该让所有的 Observer
存活,那么你需要传递 std::shared_ptr<Observer>
,而不是 Observer &
。
如果你确定你的 Observer
总是比你的 Subject
长寿,或者总是可以在他们死前调用 removeObserver
,那么你仍然可以通过 Observer &
,并且存储 std::reference_wrapper<Observer>
.
如果你所有的Observer
都属于std::shared_ptr
,但你不想Subject
影响他们的生命周期,传递并存储std::weak_ptr<Observer>
。
我正在尝试用 C++ 创建一个主题-观察者系统,就像 C# 中的事件系统一样。 观察者 class:
template <class T>
class Observer {
int id;
public:
static int nextId;
Observer() : id(nextId++) {}
virtual void handleEvent(const T&) = 0;
virtual ~Observer();
};
主题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&);
};
问题是当我尝试实现时 addObserver
我不知道如何将引用添加到集合中。
我知道 make_shared<Observer<T>>
正在创建一个新实例,所以当我尝试 make_shared<Observer<T>>(observer)
时,我在尝试创建抽象时遇到错误 class :
error: invalid new-expression of abstract class type ‘Observer’
我试过 shared_ptr<Observer<T>> observerPtr(observer)
但效果不佳:
error: no matching function for call to ‘std::shared_ptr >::shared_ptr(Observer&)’
如何从派生自抽象 class 的对象的引用创建 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
}
how can I create a shared_ptr from a reference of an object derived from an abstract class?
一般来说,你不能。指向抽象基的共享指针只能指向具体实例。您通常无法在编译时通过基引用知道具体类型。
您可能应该更改接口,以便函数接受共享指针而不是引用作为参数。
如何从派生自抽象 class 的对象的引用创建 shared_ptr?
You cannot create a shared_ptr to an abstract class.
但是您可以做一些事情来完成代码工作。
一个可能的解决方案是定义base class Observer not abstrastct,删除 =0
。然后为了确保您实际的纯虚函数不会以一种不好的方式在 base class Observer 上调用,您可以在 base class Observer 的方法的实现中抛出异常。因此,当在 Observer class 上调用时,它会引发异常,在另一种情况下(例如在 AirConditioner class) 它会在不引发异常的情况下完成工作。
注意:这只是这种情况的一种解决方法,请尝试重新考虑您的代码设计以获得更好的实现
要回答有关实现 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>>
作为 [=13= 的参数传递].如果你必须使用 addObserver(Observer<T>&)
接口并且你希望 "observers" 集共同管理观察者对象的生命周期,你可以使用 std::enable_shared_from_this 并使 Observer 成为 [=22] 的子类=].
希望对您有所帮助。
C# 可以很容易地忽略 Subject
中 Observer
的生命周期,并且事情(大部分)会没问题。 C++ 不允许您忽略生命周期。
如果 Subject
应该让所有的 Observer
存活,那么你需要传递 std::shared_ptr<Observer>
,而不是 Observer &
。
如果你确定你的 Observer
总是比你的 Subject
长寿,或者总是可以在他们死前调用 removeObserver
,那么你仍然可以通过 Observer &
,并且存储 std::reference_wrapper<Observer>
.
如果你所有的Observer
都属于std::shared_ptr
,但你不想Subject
影响他们的生命周期,传递并存储std::weak_ptr<Observer>
。