在C++有没有办法让孩子重用祖父中定义的纯虚函数的 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

本文关键字:定义 函数 实现 Parent 有没有 C++ 孩子      更新时间:2023-10-16

考虑下面的代码,EventGeneratorBase 是一个帮助程序类,旨在为AddEventHandler()提供实际的实现,我想在类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;
}

您的问题是您的RemoteControl对象中有两个不同的 IEventGenerator<IControlEvents> 类型的子对象。 一个通过EventGeneratorBase<IControlEvents>,一个通过IRemoteControl

有两种方法可以防止您有两个不同的子对象。 首先是继承virtual ly,从两个地方的IEventGenerator<TEventHandler>。 这具有适度的运行时成本。 只需在每次从IEventGenerator<?>继承之前添加virtual,您就完成了。

第二种方法是注意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>
{

并改变我们的继承方式。 我们现在在我们和IRemoteControl之间插入EventGeneratorHelper,所以它们现在共享相同的共同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();
    });
  }
};

我认为这很好 - 要求客户知道正确的迭代方式似乎很愚蠢。

继承层次结构中有问题。

template <class TEvents> struct EventGeneratorBase :IEventGenerator<TEvents> {
    [...]
};
struct IRemoteControl  : IEventGenerator<IControlEvents> { 
    [...]
};
struct RemoteControl : IRemoteControl, EventGeneratorBase<IControlEvents> {
    [...]
};

这不是你所期望的。相反,您的类RemoteControlIEventGenerator继承两次,一次从IRemoteControl继承,一次从EventGeneratorBase继承。