C++ 函数指针参数和类继承自动转换
Posted
技术标签:
【中文标题】C++ 函数指针参数和类继承自动转换【英文标题】:C++ Function pointer arguments and classes inheritance automatic cast 【发布时间】:2019-12-13 10:32:51 【问题描述】:首先抱歉,如果问题的名称不够清楚。我真的不知道如何称呼这个问题。
所以我在一个类中有一个函数指针,它像一个 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 中自动进行从父级到子级的强制转换,所以我不必为我调用的每个函数都这样做。
谢谢!
【问题讨论】:
如果你总是想在回调中使用Child*
,为什么不相应地更改签名呢?
嗨@dave,我的项目中有 16-18 个子类,它们最终会执行该函数。
在这种情况下,我认为没有自动的方法可以做到这一点。 (编译器如何知道要为任何给定的回调函数转换到哪个子类?)在我看来,您可能希望在 Parent
类中添加更多虚函数,因此您根本不需要转换。
听到这个消息很难过。无论如何,感谢您的帮助!
您不想使用函数指针。你想要std::function<void()>
(是的,没有参数)并且你想要传递一个带有捕获的对象的lambda。
【参考方案1】:
不要使用函数指针。相反,您想要std::function<void()>
(是的,没有参数)并传递一个带有捕获对象的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);
【讨论】:
【参考方案2】: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);
如果b
的类型不合适,动态转换将抛出std::bad_cast
- 不幸的是,这是一个相当昂贵的运行时事情,是让编译器确定指向/引用对象是否是正确类型的安全方法(通常)不可能。
【讨论】:
以上是关于C++ 函数指针参数和类继承自动转换的主要内容,如果未能解决你的问题,请参考以下文章