考虑下面的代码,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/

10-12 14:26