gpt4 book ai didi

c++ - 在 C++ 中,有没有办法让 Child 重用 GrandParent 中定义的纯虚函数的 Parent 类实现

转载 作者:行者123 更新时间:2023-11-30 01:47:53 24 4
gpt4 key购买 nike

考虑下面的代码,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>在这两个地方。这具有适度的运行时成本。只需添加 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之间, 所以他们现在共享相同的公共(public) 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com