从派生类将函数作为参数传递给父类方法

3
我有如下代码,其中execute()方法接受一个函数作为参数并执行它。然后,start()方法调用execute()以运行method1()
class Test
{
  int Test::start(void)
  {
    execute(&Test::method1);
    return 1;
  }

  void Test::execute(void(Test::*func)(void))
  {
    (this->*func)();
  }

  void Test::method1(void)
  {
    //Do something...
  }
}

现在我想修改这个代码,以实现以下目标:
  • 创建一个名为TestRunner的基类,并将execute()方法移到该类中。
  • Test继承自TestRunner,并在其中调用execute()方法来运行其本地方法。
我尝试了下面的代码,但困在了如何指定execute()方法参数上,即我现在的TestRunner::*func
class TestRunner
{
  public:
    TestRunner()
    {
       //Do something...
    }
  protected:
    void execute(void(TestRunner::*func)(void))
    {
      (this->*func)();
    }
}

class Test : TestRunner
{
    public:
      Test() : TestRunner()
      {

      }

      int start()
      {
        TestRunner::execute(&Test::method1);
        return 1;
      }

    private:
      void method1(void)
      {
        //Do something
      }    
}

如果我按照现有的代码编译,显然会出现以下错误:
- "no matching function for call to 'Test::execute(void (Test::*)())'" - "no known conversion for argument 1 from 'void (Test::)()' to 'void (TestRunner::)()'"
请问是否有人能够指导我正确的方向,或者我需要完全改变做法才能实现我的目标?

1
虚函数有什么问题? - Mohamad Elghawi
似乎是一个XY问题 - R Sahu
@MohamadElghawi 能详细说明一下吗? - arie
@RSahu 我认为我已经很清楚地表达了我的目标和尝试的解决方案...我需要一个类继承另一个类,并且从派生类中能够调用父类中的方法并将另一个类作为参数传递给它。 - arie
@SeverusSnape,我理解那是你的实现策略。我认为那不是真正的问题。无论如何,你唯一能够通过使用CRTP或者在基类中使用virtual成员函数来实现。 - R Sahu
不要使用 TestRunner::execute(&Test::method1);,而是使用 TestRunner::execute(static_cast<void(Test::*)(void)>(&Test::method1));static_cast<> 告诉编译器你知道自己在做什么。记得将你的方法设为虚函数。 - Maelkum
2个回答

0
我在这里使用了这个答案来得出一个解决方案:C++指向成员函数的继承 创建一个回调类:
class Callback
{
    public:
        virtual ~Callback() { }
        virtual void doSomething()=0;
};

扩展回调类来定义函数执行的方式,并使用模板:
template<class T>
class BCallback: Callback
{
    public:
        ~BCallback() { }
        BCallback(T *obj, void(T::*fn)()): obj_(obj), fn_(fn) { };

        void doSomething()
        {
            (obj_->*fn_)();
        }

    private:
        T *obj_;
        void(T::*fn_)();
};

在基类中使用回调对象:
class TestRunner
{
    protected:
        void execute(Callback *cb)
        {
            cb->doSomething();
        }
};

从派生类中运行该方法:

class Test: TestRunner
{
    public:
        int start()
        {
            BCallback<Test> cb(this, &Test::method1);
            this->execute(&cb);
            return 1;
        }

    private:
        void method1(void)
        {
            //Do something
        }   
};

0
您可以像这样使用 typedef

typedef void(Test::*Callback)(void);

然后,您可以使执行函数接受类型为Callback的对象。它看起来像这样:Test::execute(Callback)

在调用时,请使用static_cast<>

Test tester;
tester.execute(static_cast<Callback>(&DerivedTest::someMethod));

示例 Test::execute(Callback) 实现:

Test::execute(Callback cb) {
    (this->*cb)();
}

这样你就可以避免编写整个两个新类(其中一个甚至是模板!)来完成简单的事情。作为奖励,您可以使用函数重载来获取不同函数签名的Test::execute


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接