c++ derived class 需要通过回调调整 base class

c++ derived class needs to tweak base class via callback

我想创建一个基础 class ==> 派生的 class 设置,其中基础 class' 构造函数具有对 运行 的回调(可能很复杂) 函数使用派生 class 中的信息修改基 class' 私有成员。但是,我 运行 陷入先有鸡还是先有蛋的问题,因为基础 class 构造函数 运行 在 派生的 class 之前 ]' 成员被初始化。下面是演示问题的代码:

#include <iostream>
#include <functional>

class B
{
  public:
    typedef std::function<void(std::string &)> mod_func_t;

    B(const mod_func_t &m) : foo("base str")
    {   
      std::cout << "Base constructor\n";
      m(foo);
      std::cout << "base constructor finally has: " << foo << std::endl;
    }   

  private:
    std::string foo;
};

class D : public B
{
  public:
    D(const std::string &input) :
      B(std::bind(&D::my_f, this, std::placeholders::_1)),
      input_(input)
    {   
      std::cout << "Derived constructor\n";
    }   

  private:
    void my_f(std::string &s) 
    {   
      std::cout << "Derived class' modification function\n";
      s += input_; // <== Crashes here because input_ is not yet constructed
    }   

    const std::string input_;
};

int main()
{
  D d("my input");
  return 0;
}

正确的做法是什么?

我相信 CRTP 可以帮助您解决这个问题.. 有一个简单的例子:

#include <iostream>
#include <functional>

template <typename Derived>
class B
{
  public:
 
    B() : foo("base str")
    {   
      static_cast<Derived*>(this)->m(foo);
      std::cout << "Base constructor\n";
      std::cout << "base constructor finally has: " << foo << std::endl;
    }
    
    void m(std::string& str) { //... }   

  private:
    std::string foo;
    friend Derived;
};

class D : public B<D>
{
  public:
    D(std::string &input) :
      B(),
      input_(input)
    {   
      std::cout << "Derived constructor\n";
    }   
    void m(const std::string& str) { //... }

  private:
    void my_f(std::string &s) 
    {   
      std::cout << "Derived class' modification function\n";
      s += input_; // <== Crashes here because input_ is not yet constructed
    }   

    const std::string input_;
};

int main()
{
  D d("my input");
  return 0;
}

一种方法是在调用B的构造函数之前让D计算调整后的string

class D : public B {
  D(std::string str)
   : B(my_f(str))
  {}

  std::string my_f(std::string str) { return str + "..."; }
};

第二种方法是让构造函数 D 的主体做一些工作。这里 adjust_base 也可以是 virtual.

class D : public B {
  D(std::string str)
   : B(str)
  {
     adjust_base();
  }

  void adjust_base();
};