【Qt】成员函数指针

一、成员函数指针的本质

与普通函数指针的区别

cpp 复制代码
// 普通函数指针
void (*funcPtr)() = &普通函数;

// 成员函数指针
void (MyClass::*memberFuncPtr)() = &MyClass::成员函数;

绑定对象 :成员函数指针必须与类的实例对象 结合使用

隐含 this 指针:成员函数指针内部隐含了访问对象成员数据的上下文


二、完整语法解析

声明格式
cpp 复制代码
返回类型 (类名::*指针变量名)(参数列表) [const];

示例 1:无参函数

cpp 复制代码
void (Teacher::*teachSignal)() = &Teacher::hungry;

示例 2:带参数的函数

cpp 复制代码
void (Student::*studySlot)(int hours) = &Student::learn;

示例 3:const 成员函数

cpp 复制代码
QString (DataModel::*getData)() const = &DataModel::data;

三、核心使用场景

1. Qt 信号槽连接(Qt5+ 风格)
cpp 复制代码
QObject::connect(
    sender对象指针, 
    &发送者类::信号,  // 这里本质是成员函数指针
    receiver对象指针, 
    &接收者类::槽函数
);

优势

• 编译时类型检查

• 自动参数类型匹配

• 不需要 SIGNAL()/SLOT()

2. 实现回调机制
cpp 复制代码
class Button {
public:
    void onClick(void (User::*handler)()) {
        // 保存回调函数指针
        m_handler = handler;
    }

    void trigger(User* user) {
        (user->*m_handler)(); // 通过对象调用成员函数
    }

private:
    void (User::*m_handler)();
};

四、操作成员函数指针

赋值与调用
cpp 复制代码
class Calculator {
public:
    double add(double a, double b) { return a + b; }
    double mul(double a, double b) { return a * b; }
};

// 定义成员函数指针类型
using MathOp = double (Calculator::*)(double, double);

int main() {
    Calculator calc;
    
    // 赋值不同操作
    MathOp operation = &Calculator::add;
    double result = (calc.*operation)(3, 4); // 输出 7.0

    operation = &Calculator::mul;
    result = (calc.*operation)(3, 4); // 输出 12.0
}
在数据结构中使用
cpp 复制代码
#include <map>

class AudioPlayer {
public:
    void play() { /*...*/ }
    void pause() { /*...*/ }
    void stop() { /*...*/ }
};

std::map<int, void (AudioPlayer::*)()> controlMap {
    {1, &AudioPlayer::play},
    {2, &AudioPlayer::pause},
    {3, &AudioPlayer::stop}
};

// 使用示例
AudioPlayer player;
(player.*controlMap[1])(); // 执行 play()

五、特殊注意事项

1. 继承关系处理
cpp 复制代码
class Base {
public:
    virtual void foo() { cout << "Base"; }
};

class Derived : public Base {
public:
    void foo() override { cout << "Derived"; }
};

// 成员函数指针支持多态
void (Base::*funcPtr)() = &Base::foo;
Derived obj;
(obj.*funcPtr)(); // 输出 "Derived"
2. 静态成员函数
cpp 复制代码
class Logger {
public:
    static void writeLog() { /*...*/ } 
};

// 静态成员函数使用普通函数指针
void (*logFunc)() = &Logger::writeLog;
3. 现代 C++ 的改进

使用 auto 简化声明:

cpp 复制代码
auto funcPtr = &MyClass::memberFunction; // 自动推导类型

六、底层原理(扩展知识)

成员函数指针在内存中实际存储的是:

• 函数在类中的偏移量

• 虚函数表索引(如果是虚函数)

• 调整 this 指针的偏移量(多重继承时)

这种实现方式使得成员函数指针比普通函数指针占用更多内存(通常 2-3 个机器字长),具体细节由编译器实现决定。


七、Qt 中的典型应用

信号/槽参数匹配规则
cpp 复制代码
// 参数类型必须严格匹配
void (Sender::*signal)(int) = &Sender::valueChanged;
void (Receiver::*slot)(int) = &Receiver::updateValue;

QObject::connect(sender, signal, receiver, slot); // 正确

// 以下会导致编译错误
void (Receiver::*wrongSlot)(QString) = &Receiver::wrongUpdate;
QObject::connect(sender, signal, receiver, wrongSlot); // 错误!参数类型不匹配

通过深入理解成员函数指针,可以更好地掌握 Qt 的信号槽机制以及 C++ 的面向对象特性。这种指针类型虽然语法略显复杂,但为类型安全的高阶抽象提供了坚实基础。

相关推荐
2601_962071574 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
淡海水5 小时前
07-04-并发-ConcurrentBag-T-工作窃取WorkStealing算法
开发语言·算法·c#·bag·concurrent·workstealing
CS_Zero6 小时前
C语言sizeof是函数吗?
c语言·开发语言
-今昭-7 小时前
《V2V 迁移实战:将 VMware 虚拟机转为 OpenStack 可用 Glance qcow2 镜像》
开发语言·python
黑马程序员毕设8 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
_Twink1e9 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
问天_观心9 小时前
大模型微调学习(一)
开发语言·人工智能·学习·语言模型·github
阿里嘎多学长9 小时前
2026-09-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
大丑哥10 小时前
QT QML 中实现高亮功能
qt
源代码•宸10 小时前
前置准备:定时微服务背景和现状
开发语言·经验分享·后端·微服务·云原生·架构·golang