考虑下面的代码,EventGeneratorBase是一个帮助程序类,旨在提供AddEventHandler()
的实际实现,我想在RemoteControl
类中使用该实现,而不是显式定义它。我知道在不定义方法的情况下无法实例化RemoteControl
,但是有没有捷径或简便的方法来避免手动定义方法。
注意:当前格式的代码无法编译,因为无法实例化RemoteControl。
#include <iostream>
#include <vector>
#include <memory>
template<class TEventHandler> struct IEventGenerator {
virtual ~IEventGenerator() = default;
virtual void AddEventHandler(std::weak_ptr<TEventHandler> eventHandler) = 0;
};
template <class TEvents> struct EventGeneratorBase : IEventGenerator<TEvents> {
void AddEventHandler(std::weak_ptr<TEvents> target) {
_eventHandlers.push_back(target);
}
std::vector<std::weak_ptr<TEvents>> GetEventHandlers() {
return _eventHandlers;
}
private:
std::vector<std::weak_ptr<TEvents>> _eventHandlers;
};
struct IControlEvents {
virtual ~IControlEvents() = default;
virtual void PowerOn() = 0;
virtual void PowerOff() = 0;
};
struct IRemoteControl : IEventGenerator<IControlEvents> {
virtual ~IRemoteControl() = default;
virtual void Toggle() = 0;
};
struct RemoteControl : IRemoteControl, EventGeneratorBase<IControlEvents> {
// I don't want to define AddEventHandler() in this class and
// would like to inherit the implementation from EventGeneratorBase
void Toggle() {
for (auto tref : GetEventHandlers()) {
auto t = tref.lock();
if (t) {
t->PowerOn();
t->PowerOff();
}
}
}
};
struct Light : IControlEvents {
Light(std::string color) : _color(color) { }
void PowerOn() {
std::cout << _color << "::Light ON!" << std::endl;
}
void PowerOff() {
std::cout << _color << "::Light OFF!" << std::endl;
}
private:
std::string _color;
};
int main() {
std::shared_ptr<IRemoteControl> remote(new RemoteControl); // ERROR: Can't instantiate
std::shared_ptr<IControlEvents> light1(new Light("GREEN"));
std::shared_ptr<IControlEvents> light2(new Light("RED"));
remote->AddEventHandler(light1);
remote->AddEventHandler(light2);
remote->Toggle();
return 0;
}
最佳答案
您的问题在于,您的IEventGenerator<IControlEvents>
对象中有RemoteControl
类型的两个不同的子对象。一种通过EventGeneratorBase<IControlEvents>
,另一种通过IRemoteControl
。
有两种方法可以防止您拥有两个不同的子对象。首先是在两个位置都从virtual
继承IEventGenerator<TEventHandler>
ly。这具有适度的运行时成本。只需在从virtual
继承的每种情况下添加IEventGenerator<?>
即可完成。
第二种方法是注意EventGeneratorBase
旨在帮助实现IEventGenerator
。
template<class T> struct tag{using type=T;};
template<class Tag> using type_t=typename Tag::type;
template<class TEventHandler>
tag<TEventHandler> get_event_handler_type(
IEventGenerator<TEventHandler> const*
) { return {}; }
template<class X>
using event_handler_type = type_t< decltype( get_event_handler_type( (X*)nullptr ) ) >;
template <class Base, class TEvents = event_handler_type<Base>>
struct EventGeneratorHelper :
Base
{
void AddEventHandler(std::weak_ptr<TEvents> target) override {
_eventHandlers.push_back(target);
}
std::vector<std::weak_ptr<TEvents>> GetEventHandlers() {
return _eventHandlers;
}
private:
std::vector<std::weak_ptr<TEvents>> _eventHandlers;
};
现在,转到此处:
struct RemoteControl :
EventGeneratorHelper<IRemoteControl>
{
并改变我们的继承方式。现在,我们在我们和
EventGeneratorHelper
之间插入了IRemoteControl
,因此它们现在共享相同的公用IEventGenerator
。这消除了对
virtual
继承的需要,但是却增加了编译时间,并可能导致某些可执行代码膨胀。我们可以更进一步。将此添加到
EventGeneratorHelper
:template<class Action>
void FireEvents( Action&& action ) const {
for (auto tref : GetEventHandlers()) {
auto t = tref.lock();
if (t) {
action(t);
}
}
}
将
RemoteControl
减少为:struct RemoteControl :
EventGeneratorHelper<IRemoteControl>
{
void Toggle() {
this->FireEvents([](std::shared_ptr<IRemoteControl> const& ptr){
t->PowerOn();
t->PowerOff();
});
}
};
我认为这很好–要求客户知道正确的迭代方式似乎很愚蠢。
关于c++ - 在C++中,Child是否有办法重用GrandParent中定义的纯虚函数的Parent类实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31010988/