前言
在C语言中,曾感受过函数指针的威力。C++也并未摒弃这一强大的开发特性。众所周知,在C++中允许定义类这一种新型的数据类型。那么,在类中定义的函数应当也可以被函数指针所指向并调用。
本文就函数指针与类成员函数指针之间的联系与区别展开讨论。
函数指针回顾
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void foo1(int a = 1) { std::cout<<"foo1 test: "<<a<<std::endl; } int main() { foo1(); void (*fooP)(int) = foo1; fooP(2); }
|
以上代码样例,展示了函数指针的使用方法。接下来。我们接着讨论类成员函数。
类成员函数指针
在C++中,通过基类指针或引用可指向派生类指针或引用【隐式向上转换】实现多态。我们不得不提出一个问题,也即在指针函数中,是否也会存在类似于多态的问题。
接下来是一段代码,请越过它,跟随代码后的分析阅读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| class Animal { public: int value; void speak() { cout << "I am a Animal!" << endl; printf ("%d\n", &Animal::speak); } virtual void eat() { cout << "Animal eat xxx" << endl; } Animal() { value = 1; } }; class Cat: public Animal { public: void speak() { cout << "I am a Cat" << endl; } virtual void eat() { cout << "Cat eat fish" << endl; } Cat() { value = 2; } }; typedef void (Animal::*aP)(); typedef void (Cat::*cP)(); int main() { Animal ae; aP iap; iap = &Animal::speak; (ae.*iap)(); Cat ce; cP icp; icp = (void (Cat::*)())iap; (ce.*icp)(); iap = &Animal::eat; (ae.*iap)(); icp = &Cat::eat; (ce.*icp)(); icp = (void (Cat::*)())iap; (ce.*icp)(); return 0; }
|
在代码中,我们定义了两个类Cat & Animal。并定义Animail类中的eat函数为虚且在Cat类中重新定义了eat函数。
1 2
| typedef void (Animal::*aP)(); typedef void (Cat::*cP)();
|
定义新数据类型Animal函数指针与Cat函数指针分别为aP与cP
1 2 3 4 5 6 7
| Animal ae; aP iap; iap = &Animal::speak; (ae.*iap)();
|
将Animail中的speak函数地址绑定到iap函数指针中,并调用。
1 2 3 4 5 6 7
| Cat ce; cP icp; icp = (void (Cat::*)())iap; (ce.*icp)();
|
将iap【Animail函数指针】强制转换为Cat函数指针并赋值于icp,调用icp。
经过观察可知,两个输出的结果相同。其原因为:对于动态成员函数,函数地址在编译之前便确定了。
ps:关于该问题,请参阅C++类中的函数地址问题
1 2 3 4 5 6 7 8 9 10 11 12
| iap = &Animal::eat; (ae.*iap)(); icp = &Cat::eat; (ce.*icp)(); icp = (void (Cat::*)())iap; (ce.*icp)();
|
首先强调eat函数为虚函数,虚函数常被用于多态。
代码分别绑定iap & icp指针于Animal & Cat eat函数上。输出结果符合预期。
而后将iap指针强制转换为Cat::*函数指针后,输出结果转变为Cat类中的eat函数,其原因是虚函数运行函数在运行阶段决定,与上述的动态函数的行为有决定性的差异。
结
在撰写该文章时,借鉴了:如何使用指向类的成员函数的指针(详解!)一文,深刻的体会到了C++的博大精深,以及自己在输出这些概念时的不顺畅。希望自己日后多多精进。该文章中同事推荐了,深入探索C++对象模型,日后有机会必定拜读。