模拟虚拟方法的构造函数行为

时间:2017-08-31 17:39:45

标签: c++ c++11 constructor c++14 virtual

我目前正在使用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中的实现将被丢弃(即不被调用)。所以基本上我想要实现的是类似构造函数的行为,我可以在类层次结构中的不同位置覆盖相同的方法,并且所有这些都被调用。

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

注意:不要过分关注add示例。问题是关于回调的结构,而不是add

4 个答案:

答案 0 :(得分:3)

我只会打电话给父母onAdd()

GROUP BY AccountNumber, CurrentBalance, A.ActualTagDeposit

如果您希望其他开发人员从您的基类继承,这可能会有点混乱。但对于小型私有层次结构,它可以完美运行。

我有时会使用using语句来使其更明确

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

答案 1 :(得分:2)

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 ++编译器编写每个实例版本或每个类版本,而无需自己编写。

有C ++ 20提案涉及反思和具体化,加上元类提议,可能涉及自动编写这样的代码(基于每个实例和每个类)。

Here是这项测试技术的实例:

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 ++不会为你编写它。

答案 2 :(得分:1)

如果你想要一个通用的解决方案,也许你可以使用CRTP和可变参数模板而不是运行时多态性。

this answerthis answer获取灵感:

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);

Live demo

答案 3 :(得分:0)

以下解决方案使用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()