首页 > 解决方案 > C++ 函数指针参数和类继承自动转换

问题描述

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

所以我在一个类中有一个函数指针,它像一个 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++classinheritancecallback

解决方案


奇怪地重复出现的模板模式可能是一种选择。但是,您将为每个派生类创建单独的基类,因此您不能多态地使用它们——除非您提供一个单独的公共基类。如果循环模板函数覆盖了基础中的虚拟函数,您可能最终会到达您想要获得的位置:

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_castif bis of in proper type - 不幸的是,这是一个相当昂贵的运行时事情,让编译器确定指向/引用的对象是否(通常)是正确类型的安全方法是不可能的。


推荐阅读