模拟虚拟方法的构造函数

Simulate constructor behaviour for virtual methods

本文关键字:构造函数 方法 虚拟 模拟      更新时间:2023-10-16

我目前正在使用C 进行一个小型私人项目,我提出了以下结构:

#include <iostream>
class A
{
    std::vector<int> vec;
protected:
    virtual bool onAdd(int toAdd) {
        // should the 'adding' be suppressed?
        // do some A specific checks
        std::cout << "A::onAdd()" << std::endl;
        return false; 
    }
public:
    void add(int i) {
        if(!onAdd(i)) {
            // actual logic
            vec.push_back(i);
        }
    }
};
class B : public A
{
protected:
    bool onAdd(int toAdd) override {
        // do some B specific checks
        std::cout << "B::onAdd()" << std::endl;
        return false;
    }
};

在此示例中,onAdd基本上是为add的回调,但以更多态的方式。

C类从B继承并希望覆盖onAdd时,实际问题就会出现。在这种情况下,在调用C::add时,B中的实现将被丢弃(即未调用)。因此,基本上我想实现的是一种类似构造函数的行为,我能够在类层次结构中的不同位置覆盖相同的方法,所有这些方法都被称为。

我现在的问题是:实现这一目标有可能/设计吗?我相信它不会像级联构造函数那样容易。

NOTE :不要过多地关注add示例。问题是关于回调的结构,而不是使用add是否有意义。

我只会叫我的父母onadd()

bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}

,如果您期望其他开发人员从基类继承,这可能会有些困惑。但是对于小型私人层次结构,它可以很好地工作。

我有时包括一个使用语句,以使其更加明确

class C : public B
{
  using parent=B;
  bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
struct RunAndDiscard {
  template<class Sig, class...Args>
  void operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
    if (start==finish) return;
    for (auto* i = start; i != (finish-1); ++i) {
      (*i)(args...);
    }
    (*(finish-1))(std::forward<Args>(args)...);
  }
};
template<class Sig, class Combine=RunAndDiscard>
struct invokers {
  std::vector<Sig*> targets;
  template<class...Args>
  decltype(auto) operator()(Args&&...args)const {
    return Combine{}( targets.data(), targets.data()+targets.size(), std::forward<Args>(args)... );
  }
};
struct AndTogetherResultWithShortCircuit {
  template<class Sig, class...Args>
  bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
    if (start==finish) return true;
    for (auto* i = start; i != (finish-1); ++i) {
      if (!(*i)(args...)) return false;
    }
    return (*(finish-1))(std::forward<Args>(args)...);
  }
};

这将创建一个每件事表,要做onAdd

创建每级表更难;您需要使用父母类型的表格链接,这需要每类样板。

没有办法让C 编译器编写每种现代版本或每级版本,而无需自己操作。

有20个提案,涉及反射和重新化,以及掌层提案,可能涉及这样的写作代码(以每种结构和每类为基础)。

这是该技术正在测试的现场示例:

struct AndTogetherResultWithShortCircuit {
  template<class Sig, class...Args>
  bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
    if (start==finish) return true;
    for (auto* i = start; i != (finish-1); ++i) {
      if (!(*i)(args...)) return false;
    }
    return (*(finish-1))(std::forward<Args>(args)...);
  }
};
class A {
  std::vector<int> vec;
protected:
  invokers<bool(A*, int), AndTogetherResultWithShortCircuit> onAdd;
public:
  void add(int i) {
    if (!onAdd(this, i)) {
      vec.push_back(i);
    }
  }
};
class B : public A
{
public:
   B() {
     onAdd.targets.push_back([](A* self, int x)->bool{
       // do some B specific checks
       std::cout << "B::onAdd(" << x << ")" << std::endl;
        return x%2;
     });
   }
};
class C : public B
{
public:
   C() {
     onAdd.targets.push_back([](A* self, int x)->bool{
       // do some B specific checks
       std::cout << "C::onAdd(" << x << ")" << std::endl;
       return false;
     });
   }
};

当您想编写自己的OO系统时,可以在C 中,但是C 不为您编写。

如果您想要一个通用解决方案,也许可以将CRTP与variadic模板一起使用,而不是运行时多聚生物学。

从这个答案中汲取灵感和此答案:

template<class... OnAdders> class A : private OnAdders... {
    std::vector<int> vec;
   template<class OnAdder>
   bool onAdd(int toAdd){
     return static_cast<OnAdder*>(this)->onAdd(toAdd);
   }
   template<typename FirstOnAdder, typename SecondOnAdder, class... RestOnAdders>
   bool onAdd(int toAdd){
     if (onAdd<FirstOnAdder>(toAdd))
        return true;
     return onAdd<SecondOnAdder, RestOnAdders...>(toAdd);
   }
public:
    void add(int i) {      
        if (onAdd<OnAdders...>(i))
          return;       
        // actual logic
        vec.push_back(i);
    }
};
class B {
public:
    bool onAdd(int toAdd) {
        // do some B specific checks
        std::cout << "B::onAdd()" << std::endl;
        return false;
    }
};

您可以使用:

A<B,C> a;
a.add(42);

实时演示。

以下解决方案使用std::function在每个构造函数期间添加每个回调:

#include <iostream>
#include <vector>
#include <functional>
class A
{
    std::vector<int> vec;
protected:
    bool onAdd(int toAdd) 
    {
        // do some A specific checks
        std::cout << "A::onAdd()" << std::endl;
        return true;
    }
    // vector of callback functions. Initialized with A::onAdd() callback as the first entry
    std::vector<std::function<bool(int)>> callbacks{{[this](int toAdd){return onAdd(toAdd); }}};
public:
    void add(int i) 
    {
        for(auto& callback : callbacks) {
            if(!callback(i))
                return;
        }
        // actual logic
        vec.push_back(i);
    }
};
class B : public A
{
public:
    B()
    {
        callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
    }
protected:
    bool onAdd(int toAdd)  
    {
        // do some B specific checks
        std::cout << "B::onAdd()" << std::endl;
        return true;
    }
};
class C : public B
{
    public:
    C()
    {
        callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
    }
protected:
    bool onAdd(int toAdd)  
    {
        // do some C specific checks
        std::cout << "C::onAdd()" << std::endl;
        // must also call B::onAdd()
        return true;
    }
};
int main()
{
    C c;
    c.add(5);
}

打印:

A::onAdd()
B::onAdd()
C::onAdd()