简体   繁体   中英

Pass function as parameter to parent method from derived class

I have the following code, where the execute() method accepts a function as a parameter and executes it. The start() method then calls execute() in order to run 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...
  }
}

Now I want to modify this so I achieve the following:

  • Create a base class called TestRunner and and move the execute() method to it
  • Have Test inherit from TestRunner , where it can call the execute() method to run its local methods

I am trying the following, but got stuck in how I should specify the method parameter in execute() ie what right now I have as 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
      }    
}

If I compile the code like it is I obviously get these errors:

no matching function for call to 'Test::execute(void (Test::*)())'

and

no known conversion for argument 1 from 'void (Test:: )()' to 'void (TestRunner:: )()'

Can anyone guide me in the right direction here or do I need to do something completely different to achieve what I want?

I've used this answer here to come up with a solution: C++ Pointers to Member Functions Inheritance

Create a callback class:

class Callback
{
    public:
        virtual ~Callback() { }
        virtual void doSomething()=0;
};

Extend the callback class to define how a function is executed and use a template:

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_)();
};

Use a callback object in the base class:

class TestRunner
{
    protected:
        void execute(Callback *cb)
        {
            cb->doSomething();
        }
};

Run the method from the derived class:

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

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

You can use a typedef like this:

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

You can then make your executing function take objects of type Callback . It will look like this Test::execute(Callback) .

When calling it, use static_cast<> :

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

Example Test::execute(Callback) implementation:

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

This way you can avoid writing whole two new classes (one of them a template, even!) just to do a simple thing. As a bonus, you can use function overloading to get Test::execute for different function signatures.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM