C ++函数指针参数和类继承自动转换

问题描述 投票:0回答:2

首先,如果问题的名称不够清楚,请对不起。我真的不知道如何称呼这个问题。

因此,我在类内有一个函数指针,该类的工作方式类似于我使用从父类派生的某些参数(如本例中这样的参数)调用的java回调:

class Parent;

using f_Call = void(*)(Parent*);

class Parent
{
public:
    void setCallback(f_Call call)
    {
        mOnCall = call;
    }

protected:
    f_Call mOnCall = nullptr;
};

class Child1 : Parent
{
public:
    void doSomething()
    {
        // some work..
        if (mOnCall)
            mOnCall(this);
    }
};

void onCallExe(Parent* p)
{
    Child1* child = (Child1*)p;
    // do some more work...
}

int main()
{
    Child1 child;
    child.setCallback(onCallExe);
    child.doSomething();
}

我的问题是c ++是否可以在onCallExe中自动执行从父对象到子对象的转换,因此我不必为我调用的每个函数都进行转换。

谢谢!

c++ class inheritance callback
2个回答
1
投票

不要使用函数指针。相反,您需要std::function<void()>(是的,without参数),并将其传递给带有captured对象的lambda。

using f_Call = std::function<void()>;

class Parent { 
public:
      void setCallback(f_Call call) {
           mOnCall = call;
      }
      protected:
          f_Call mOnCall;
};

class Child1 : public Parent {
public:
      void doSomething() {
           // some work..
           if (mOnCall)
               mOnCall(); // no argument!
       }
};

int main()  {
    Child1 child;
    child.setCallback([&child](){ /* do whatever with the child */ });
    child.doSomething();
}

如果需要,您可以在函数模板中隐藏lambda的创建。

template <class Obj, class CB>
void setCallback (Obj& obj, CB cb) {
     obj.setCallback([&obj](){cb(obj);});
}

然后将带有Child参数的任何旧函数传递给全局setCallback模板。

void onCallExe(Child1& child) { 
    // do some more work...
}

Child1 child;
setCallback(child, onCallExe);

1
投票

Curiously recurring template pattern可能是一个选项。但是,您将为每个派生的类创建单独的基类,因此您不能多态使用它们-除非您提供单独的通用基类。如果循环模板功能覆盖了基础中的虚拟模板,那么您可能会到达想要的位置:

struct Base
{
    virtual ~Base() { }
    virtual void f() = 0;
};

template <typename T>
struct Intermediate : Base
{
    void f() override
    {
        if(callback)
            callback(static_cast<T*>(this));
    }
    void setCallback(void(*c)(T*))
    {
        callback = c;
    }

private:
    void(*callback)(T*) = nullptr;
};

struct Derived : Intermediate<Derived>
{
};

void g(Derived*) { }

void demo()
{
    Derived d;
    d.setCallback(g);
    d.f();
}

((如果不需要多态性,则可以跳过Base类-这样f也不必是虚拟的。)

唯一地,如果您想通过指针或对Base的引用来设置回调,则会遇到麻烦,因为您无法使用虚拟模板成员函数。尽管可以提供独立的帮助器功能,但您可以:

template <typename T>
void setCallback(Base& b, void(*callback)(T*))
{
    dynamic_cast<Intermediate<T>&>(b).setCallback(callback);
}

如果std::bad_cast的类型不合适,则动态转换将抛出b –不幸的是,这是相当昂贵的运行时事物,让编译器确定指向/引用的对象是否为正确类型的安全方法(通常)是不可能。

© www.soinside.com 2019 - 2024. All rights reserved.