跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 工具系统 > 运营工具 > C/C++中重载函数取地址的方法

C/C++中重载函数取地址的方法

时间:2024-04-04 16:15:50 来源:网络cs 作者:纳雷武 栏目:运营工具 阅读:

标签: 地址  方法  函数 

目录

1.现象

2.指定参数取函数地址

3.利用Qt的类QOverload


1.现象

        函数重载在C/C++编码中是非常常见的,但是我们在std::bind或std::function绑定函数地址的时候,直接取地址,程序编译就会报错,示例如下:

class CFunc12345{public:void func12345(int x) {std::cout << x;}void func12345(double x) {std::cout << x;}};void func67890(int x) {std::cout << x;}void func67890(double x) {std::cout << x;}int main(){    CFunc12345 x1;auto p = std::bind(&CFunc12345::func12345, x1, std::placeholders::_1); //[1]编译报错p(14124);    auto p1 = std::bind(&func67890, std::placeholders::_1);  //[2]编译报错p1(33333333);    std::function<void(int)> p2(&func67890);  //[3]编译报错p2(33333333);    return 0;}

上述代码[1],[2],[3]处都会出现编译错误,那是因为函数重载,多个函数名相同,找不到该用那个函数地址。这个时候解决办法就是人为指定用那个函数,那么人为指定用那个函数有哪些办法呢?

2.指定参数取函数地址

方法如下:

    //方法1:    CFunc12345 x1;using FUNC1 = void (CFunc12345::*)(int);FUNC1 func1 = &CFunc12345::func12345;auto p1 = std::bind(func1, x1, std::placeholders::_1);p1(14124);using FUNC2 = void(*)(int);FUNC2 func2 = &func67890;auto p2 = std::bind(func2, std::placeholders::_1);p2(14124);FUNC2 func3 = &func67890;std::function<void(int)> p3(func3);p3(14124);

从代码可以看出,就是手动指定函数类型,先取到函数地址后,再把地址传入指定的对象(如std::bind、std::function等)中,避免了std::bind或std::function去判断函数类型,从而避免了编译错误。

3.利用Qt的类QOverload

        QOverload是Qt5中提供的一种用于重载信号和槽函数连接的方式。它允许开发者在使用信号与槽机制时,更灵活地处理函数重载的情况。通过将信号和槽函数的参数类型转换为指定类型,QOverload实现了对信号和槽函数的类型安全检查。

        在实际应用中,QOverload通过重载调用QOverload::of,利用它来指定多个信号版本中的具体哪种类型参数。例如,当有一个信号函数被重载,具有多个不同参数类型的版本时,可以使用QOverload来明确指定要连接的是哪个版本的信号函数。

        QOverload的作用就是指定重载函数中的函数类型,从它的源码中可以看出来,源码如下:

template <typename... Args>struct QNonConstOverload{    template <typename R, typename T>    Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }    template <typename R, typename T>    static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }};template <typename... Args>struct QConstOverload{    template <typename R, typename T>    Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...) const) const Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }    template <typename R, typename T>    static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...) const) Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }};template <typename... Args>struct QOverload : QConstOverload<Args...>, QNonConstOverload<Args...>{    using QConstOverload<Args...>::of;    using QConstOverload<Args...>::operator();    using QNonConstOverload<Args...>::of;    using QNonConstOverload<Args...>::operator();    template <typename R>    Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }    template <typename R>    static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr)    { return ptr; }};

顾名思义,模版类QNonConstOverload是取不带const的类成员函数的地址的,模版类QConstOverload是取带const的类成员函数的地址的,QOverload是取普通函数地址的,它们之间的关系如下图所示:

于是上面编译错误的代码可以修改为:

int main(){    //方法2CFunc12345 x1;auto p = std::bind(QOverload<int>::of(&CFunc12345::func12345), x1, std::placeholders::_1);p(14124);auto p1 = std::bind(QOverload<int>::of(&func67890), std::placeholders::_1);p1(33333333);std::function<void(int)> p2(QOverload<int>::of(&func67890));p2(33333333);    return 0;}

QOverload看似只有装有Qt环境才能用,其实把源码稍加修改就可以作为标准的C++类来用,修改后的COverload源码如下所示:

template <typename... Args>struct CNonConstOverload{template <typename R, typename T>auto operator()(R(T::* ptr)(Args...)) const -> decltype(ptr){return ptr;}template <typename R, typename T>static auto of(R(T::* ptr)(Args...)) -> decltype(ptr){return ptr;}};template <typename... Args>struct CConstOverload{template <typename R, typename T>auto operator()(R(T::* ptr)(Args...) const) const -> decltype(ptr){return ptr;}template <typename R, typename T>static auto of(R(T::* ptr)(Args...) const) -> decltype(ptr){return ptr;}};template <typename... Args>struct COverload : CConstOverload<Args...>, CNonConstOverload<Args...>{using CConstOverload<Args...>::of;using CConstOverload<Args...>::operator();using CNonConstOverload<Args...>::of;using CNonConstOverload<Args...>::operator();template <typename R>auto operator()(R(*ptr)(Args...)) const -> decltype(ptr){return ptr;}template <typename R>static auto of(R(*ptr)(Args...)) -> decltype(ptr){return ptr;}};

QOverload在Qt的信号槽中也用的比较多。信号槽连接时,使用基于字符串的语法,可以显式指定参数类型。因此,使用重载信号或槽的哪一个实例是明确的。相反,使用基于模版函数的语法,必须强制转换重载信号或槽,以告诉编译器要使用哪个实例。

        例如,QLCDNumber有三个版本的display() 槽函数:

        1.QLCDNumber::display(int)

        2.QLCDNumber::display(double)

        3.QLCDNumber::display(QString)

使用信号QSlider::valueChanged()和QLCDNumber::display(int)连接,可以有如下系列方法:

     auto slider = new QSlider(this);     auto lcd = new QLCDNumber(this);     // String-based syntax     connect(slider, SIGNAL(valueChanged(int)),             lcd, SLOT(display(int)));     // Functor-based syntax, first alternative     connect(slider, &QSlider::valueChanged,             lcd, static_cast<void (QLCDNumber::*)(int)>(&QLCDNumber::display));     // Functor-based syntax, second alternative     void (QLCDNumber::*mySlot)(int) = &QLCDNumber::display;     connect(slider, &QSlider::valueChanged,             lcd, mySlot);     // Functor-based syntax, third alternative     connect(slider, &QSlider::valueChanged,             lcd, QOverload<int>::of(&QLCDNumber::display));     // Functor-based syntax, fourth alternative (requires C++14)     connect(slider, &QSlider::valueChanged,             lcd, qOverload<int>(&QLCDNumber::display));

        总的来说,QOverload是一个强大的工具,它使得在Qt中使用信号和槽机制时,处理函数重载的情况变得更加简单和直观。

本文链接:https://www.kjpai.cn/news/2024-04-04/154025.html,文章来源:网络cs,作者:纳雷武,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

文章评论