成员函数指针作为参数时,静态函数和非静态函数的区别
举个 QT 的例子(没学过QT的也不要紧,这适用于学习C++的同学),当我有两个类,Teacher 类和 Student 类。现在有一个场景就是,Teacher 类会发出信号,然后 Student 类去处理。调用的是 connect 函数。
Teacher 类:
Student 类:
//创建一个老师对象
this->tc = new Teacher(this);
//创建一个学生对象
this->st = new Student(this);
//老师饿了,学生请客的连接
connect(tc,&Teacher::hungry,st,&Student::treat);
注意这里,connect 函数的第二和第四个参数都是要传入函数指针。
但这时很多人就会产生一个疑问,传入函数指针,不就是传入函数的地址。那写 Teacher::hungry 不就是地址吗,为什么把 & 这个符号去掉就会报 error: call to non-static member function without an object argument 这个错误。
这是因为,在 C++ 中,Teacher::hungry 表示的是成员函数本身,而不是它的地址。
当你尝试直接传递 Teacher::hungry 作为函数参数时,编译器会认为你尝试调用一个非静态成员函数,但没有提供对象来调用它。这就是为什么会出现编译错误提示 “call to non-static member function without an object argument”。
而使用 &Teacher::hungry 的语法则表示获取 Teacher::hungry 成员函数的地址,并将这个地址作为成员函数指针进行传递。通过使用 & 运算符,你告诉编译器你要获取成员函数的地址,而不是直接调用它。
因此,在调用类的成员函数时,你应该使用 &ClassName::MemberFunction(类名::成员函数) 的语法来获得成员函数的地址,并将其传递给相应的函数或函数模板进行处理。这样可以确保编译器正确地解析成员函数指针,并且可以提供正确的对象来调用非静态成员函数。
如果,因为这里 Teacher 类中的 hungry 函数只是作为一个信号,取了 static 后传入 connect 函数会报错,所以就以 Student 类的 treat 函数来举例:
这里加了 static,相当于现在这个 treat 函数是静态函数。
所以可以直接这样传入,并不会报错,这是为什么呢?
如果 Student::treat 是一个静态成员函数,那么在将其传递给函数参数时,不需要使用 & 运算符获取其地址,也不需要提供对象来调用它。
静态成员函数是与类相关联的函数,而不是与类的实例(对象)相关联的。因此,你可以直接使用类名和作用域解析操作符 :: 来访问静态成员函数,而不需要提供对象。这样子直接传入,编译器自然会知道,现在指的是静态成员函数的指针。