前面一篇文章《函数的指针 》介绍了全局函数的指针,现在我们再来介绍一下成员函数的指针。
一般形式
Return_Type (Class_Name::* pointer_name) (Argument_List);
用typedef简化的形式
Typedef Return_Type (Class_Name::* FuncPtr_Type) (Argument_List);
FuncPtr_Type pFunc = NULL; //pFunc为成员函数指针的指针变量
成员函数指针的调用
(obj.*pPrint)(Argument_List); //obj为类的对象
(pObj->*pPrint)(Argument_List); //pObj为类的对象的指针
举个例子如下:
#include "stdafx.h" #include <iostream> #include <string> using namespace std; class Person { private: int age; float weight; float height; public: Person(int _age, float _weight, float _heigth) { age = _age; weight = _weight; height = _heigth; } void PrintPersonInfo() { cout << "age: " << age << " weight: " << weight << " height: " << height << endl; } }; typedef void (Person::*PrintFunc)(); PrintFunc pPrint = &Person::PrintPersonInfo; void testMemberFuncPtr() { Person child(2, 15.2, 0.45); (child.*pPrint)(); //把pPrint指针邦定到child对象 Person adult(22, 60.2, 1.75); Person* pAdult = &adult; (pAdult->*pPrint)(); //把pPrint指针邦定到pAdult指向的对象(即adult对象) }
结果:
age: 2 weight: 15.2 height: 0.45
age: 22 weight: 60.2 height: 1.75
说明:
1.在 (child.*pPrint)和 (pAdult->*pPrint)两边的括号是语法所强制要求的。
2.指向外部原函数(全局函数)的指针和指向类成员函数的指针是有很大区别的,类成员函数指针必须指向被调函数的宿主对象。因此,除了要有成员指针外还要有合法对象或对象指针。
当然,还可以把成员函数指针pPrint的定义放在Person类中,这时指针pPrint为Person类的一个成员。如下:
class Person { private: int age; float weight; float height; public: typedef void (Person::*PrintFunc)(); PrintFunc pPrint; public: Person(int _age, float _weight, float _heigth) { age = _age; weight = _weight; height = _heigth; pPrint = &Person::PrintPersonInfo; } void PrintPersonInfo() { cout << "age: " << age << " weight: " << weight << " height: " << height << endl; } }; void testMemberFuncPtr() { Person child(2, 15.2, 0.45); (child.*child.pPrint)(); //把pPrint指针邦定到child对象 Person adult(22, 60.2, 1.75); Person* pAdult = &adult; (pAdult->*pAdult->pPrint)(); //把pPrint指针邦定到pAdult指向的对象(即adult对象) }
静态成员函数指针的定义与一般的全局函数一样:
Return_Type (pointer_name) (Argument_List);
例如:
class Person { private: int age; float weight; float height; public: Person(int _age, float _weight, float _heigth) { age = _age; weight = _weight; height = _heigth; } void PrintPersonInfo() { cout << "age: " << age << " weight: " << weight << " height: " << height << endl; } static void Sleep() { cout << "Sleep..." << endl; } }; //非静态成员函数的指针 typedef void (Person::*PrintFunc)(); PrintFunc pPrint = &Person::PrintPersonInfo; //静态成员函数的指针 typedef void(*StaticMemberFuncType)(); StaticMemberFuncType pSleep = &Person::Sleep;//可以为&Person::Sleep,也可以为 void testMemberFuncPtr() { Person child(2, 15.2, 0.45); (child.*pPrint)(); //非静态成员函数的指针pPrint要邦定到类的对象child上 pSleep(); //静态成员函数的指针不需要邦定,直接调用 //(child.*pSleep)(); //expression must have point-to-memeber type }
说明:
一个静态成员函数没有 this 指针。除了它和其它的类成员共享命名空间(类名,如此例中为Person)之外,它和常规全局函数是一样的。所以,静态成员函数不是类的一部分,成员函数指针的语法对静态成员函数指针并不成立。
对于nonstatic member function (非静态成员函数)取地址,获得该函数在内存中的实际地址
对于virtual function(虚函数),其地址在编译时期是未知的,所以对于virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值。
例:
#include "stdafx.h" #include <iostream> #include <stdio.h> #include <string> using namespace std; class Person { private: int age; float weight; float height; public: Person(int _age, float _weight, float _heigth) { age = _age; weight = _weight; height = _heigth; } virtual void EatFood(string foodName) = 0; virtual void Play() { cout << "Playing..." << endl; } void PrintPersonInfo() { cout << "age: " << age << " weight: " << weight << " height: " << height << endl; } static void Sleep() { cout << "Sleep..." << endl; } }; class Student : public Person { private: int studentId; public: Student(int _age, float _weight, float _heigth, int _studentId) : Person(_age, _weight, _heigth) { studentId = _studentId; } virtual void EatFood(string foodName) { cout << "Eating " << foodName << "..." << endl; } virtual void Play() { cout << "Playing games..." << endl; } void PrintPersonInfo() { Person::PrintPersonInfo(); cout << studentId << endl; } }; void testMemberFuncPtr() { printf("Person::PrintPersonInfo: %p\n", &Person::PrintPersonInfo); printf("Person::EatFood: %p\n", &Person::EatFood); printf("Person::Play: %p\n", &Person::Play); printf("Student::PrintPersonInfo: %p\n", &Student::PrintPersonInfo); printf("Student::EatFood: %p\n", &Student::EatFood); printf("Student::Play: %p\n", &Student::Play); typedef void (Person::*PrintFuncType)(); typedef void (Person::*VirtualFuncType)(string); PrintFuncType pPlay = &Person::Play; VirtualFuncType pEatFood = &Person::EatFood; Student student(18, 60.0, 1.76, 1); (student.*pPlay)(); //调的是子类Student的Play方法 (student.*pEatFood)("vegetable"); //调的是子类Student的EatFood方法 }
结果:
Person::PrintPersonInfo: 01181190
Person::EatFood: 01181294
Person::Play: 011812E9
Student::PrintPersonInfo: 01181398
Student::EatFood: 01181294
Student::Play: 011812E9
Playing games...
Eating vegetable...
当成员函数是虚函数的时候,成员函数能够具有多态性并且可用父类的成员函数指针调用子类的方法。“一个指向虚成员的指针能在不同地址空间之间传递,只要二者使用的对象布局一样” (此话来自C++老爸 Bjarne Stroustrup 的 《C++程序设计语言》 )。 当函数是虚函数的时候,编译器会生成虚函数表,来保存虚函数的地址。这是和非虚函数之间的最大不同,因此,运行时的行为也是不同的。