简体   繁体   English

在C ++中,Child是否有办法重用GrandParent中定义的纯虚函数的Parent类实现

[英]In C++ Is there a way for the Child to reuse the the Parent class implementation of the pure virtual function defined in GrandParent

Consider the below code, EventGeneratorBase is a helper class intended to provide the actual implementation for AddEventHandler() and I would like to use that implementation in the class RemoteControl instead of explicity defining it. 考虑下面的代码,EventGeneratorBase是一个帮助程序类,旨在提供AddEventHandler()的实际实现,我想在RemoteControl类中使用该实现,而不是显式定义它。 I know it's not possible to instantiate RemoteControl without defining the method but is there a shortcut or an easy way to avoid manually defining the methods. 我知道在不定义方法的情况下无法实例化RemoteControl ,但是有没有捷径或简便的方法来避免手动定义方法。


Note: The code in it's present form doesn't compile because RemoteControl can't be instantiated. 注意:由于无法实例化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;
}

Your problem is that you have two distinct sub-objects of type IEventGenerator<IControlEvents> within your RemoteControl object. 您的问题是,在RemoteControl对象中有两个类型为IEventGenerator<IControlEvents>不同子对象。 One via EventGeneratorBase<IControlEvents> and one via IRemoteControl . 一个通过EventGeneratorBase<IControlEvents> ,另一个通过IRemoteControl

There are two ways to prevent you from having two distinct subobjects. 有两种方法可以防止您拥有两个不同的子对象。 The first is to inherit virtual ly from IEventGenerator<TEventHandler> in both spots. 首先是在两个地方都从IEventGenerator<TEventHandler>继承virtual ly。 This has a modest run-time cost. 这具有适度的运行时成本。 Simply add virtual before every case of inheritance from IEventGenerator<?> and you are done. 只需在从IEventGenerator<?>继承的每种情况下添加virtual ,即可完成。

A second method is to note that EventGeneratorBase is intended to help with implementing 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;
};

now, go down to here: 现在,转到此处:

struct RemoteControl :
  EventGeneratorHelper<IRemoteControl>
{

and change how we inherit. 并改变我们的继承方式。 We now interpose EventGeneratorHelper between us and IRemoteControl , so they now share the same common IEventGenerator . 现在,我们在IRemoteControlEventGeneratorHelper之间插入EventGeneratorHelper ,因此它们现在共享相同的公用IEventGenerator

This removes the need for virtual inheritance, but does up your compile time, and can cause some executable code bloat. 这样就消除了对virtual继承的需求,但是却增加了编译时间,并可能导致某些可执行代码膨胀。

We can go a step further. 我们可以更进一步。 Add this to EventGeneratorHelper : 将此添加到EventGeneratorHelper

template<class Action>
void FireEvents( Action&& action ) const {
  for (auto tref : GetEventHandlers()) {
    auto t = tref.lock();
    if (t) {
      action(t);
    }
  }
}

which reduces RemoteControl to: RemoteControl减少为:

struct RemoteControl :
  EventGeneratorHelper<IRemoteControl>
{
  void Toggle() {
    this->FireEvents([](std::shared_ptr<IRemoteControl> const& ptr){
      t->PowerOn();
      t->PowerOff();
    });
  }
};

which I think is nice -- requiring clients to know the right way of iterating seems silly. 我认为这很好–要求客户知道正确的迭代方式似乎很愚蠢。

You have a problem in your inheritance hierarchy. 您的继承层次结构中有问题。

template <class TEvents> struct EventGeneratorBase :IEventGenerator<TEvents> {
    [...]
};

struct IRemoteControl  : IEventGenerator<IControlEvents> { 
    [...]
};

struct RemoteControl : IRemoteControl, EventGeneratorBase<IControlEvents> {
    [...]
};

This is not doing what you might expect. 这没有达到您的期望。 Instead, your class RemoteControl inherits twice from IEventGenerator , once from IRemoteControl and once from EventGeneratorBase . 而是,类RemoteControlIEventGenerator继承两次 ,一次从IRemoteControl继承,一次从IRemoteControl EventGeneratorBase

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

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