函数指针做函数参数
程序员文章站
2022-07-07 23:40:52
多态是C++的三大法器之一,此处我们用C模拟多态,加深对C++的多态的理解 ......
1).函数指针原型:int (*myFuncVar)(int a, int b) ; //本质是一种变量,专门用做指向函数,变量名为myFuncVar。
我们可以这样定义并赋值:
int add();
int (*myFuncVar)(int a, int b) = add;
也可以这样定义并赋值:
int add();
int (*myFuncVar)(int a, int b);
myFuncVar = add;
2)作用:函数指针能用来:①当函数用作调用,成为了一般的函数调用 ② 做参数
下面是当函数用作调用:
//例1
1 #include<stdio.h> 2 #include<stdio.h> 3 int max(int x, int y){ return (x>y ? x : y); } // 定义带参数max函数 4 5 int main() 6 { 7 int(*ptr)(int, int); // 定义函数指针变量ptr,参数为两个int型数据 8 int a, b, c; 9 ptr = max; //指针变量指向函数首地址 10 scanf("%d%d", &a, &b); 11 c = (*ptr)(a, b); //等价于 c = max(a,b); 这样就成了一般的函数调用了 12 printf("a=%d, b=%d, max=%d", a, b, c); 13 return 0; 14 }
下面是用作函数的参数
//例2
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 void A(int a, int b) 6 { 7 printf("我是A,a=%d,b=%d\n", a, b); 8 } 9 void B(int a, int b) 10 { 11 printf("我是B,a=%d,b=%d\n", a, b); 12 } 13 void C(int a, int b) 14 { 15 printf("我是C,a=%d,b=%d\n",a,b); 16 } 17 18 int myMianOp( void(*myFuncVar)(int a, int b) ) //函数指针当做函数的参数 19 { 20 myFuncVar(1, 2); 21 return 0; 22 } 23 void main() 24 { 25 myMianOp(A); //调用者 //A不仅为函数名,也是函数的首地址(也称函数入口点) 26 myMianOp(B); //调用者 //B不仅为函数名,也是函数的首地址(也称函数入口点) 27 myMianOp(C); //调用者 //C不仅为函数名,也是函数的首地址(也称函数入口点) 28 29 system("pause"); 30 }
/***************************************************************************
输出如下:
我是A,a=1,b=2
我是B,a=1,b=2
我是C,a=1,b=2
****************************************************************************/
3)C++里,多态是指基类和派生类里有重写函数,而基类里的重写函数前有virtual关键字修饰,当一个函数试图调用这些重写函数时,它会根据被送进来的参数对象来执行对应的重写函数,如果参数是基类的对象就会运行基类里的重写函数,如果参数是派生类的对象就会运行派生类的重写函数。简而言之,一个函数根据参数对象会有不同的运行形态。如果没有virtual关键字修饰,则只会执行基类里的重写函数。
重写函数:必须在继承里,基类和派生类有类型名、函数名、参数均一模一样的成员函数,此类成员函数称重写函数。
虚函数:重写函数里,如果在基类的重写函数前头用virtual关键字修饰,则称这些函数名一样的成员函数为虚函数。
因此,多态成立的三个条件为:要有继承,虚函数重写,一个带参数且要试图调用重写函数的函数。
//例3 C++多态的实现
1 #include <iostream> 2 using namespace std; 3 4 5 6 7 class Parent 8 { 9 public: 10 Parent(int a=0) 11 { 12 this->a = a; 13 } 14 15 virtual void print_one() //1 动手脚 写virtal关键字 会特殊处理 //虚函数表 16 { 17 cout<<"我是爹"<<endl; 18 } 19 virtual void print_tow() //1 动手脚 写virtal关键字 会特殊处理 //虚函数表 20 { 21 cout<<"我是爹"<<endl; 22 } 23 private: 24 int a; 25 }; 26 27 class Child : public Parent 28 { 29 public: 30 Child(int a = 0, int b=0):Parent(a) 31 { 32 this->b = b; 33 } 34 35 virtual void print_one() 36 { 37 cout<<"我是儿子"<<endl; 38 } 39 private: 40 int b; 41 }; 42 43 void HowToPlay(Parent *base) 44 { 45 base->print_one(); //有多态发生 //2 动手脚 46 //效果:传来子类对 执行子类的print_one函数 传来父类对执行父类的print_one函数 47 //C++编译器根本不需要区分是子类对象 还是父类对象 48 //父类对象和子类对象分步有vptr指针 , ==>虚函数表===>函数的入口地址 49 //迟绑定 (运行时的时候,c++编译器才去判断) 50 } 51 52 void main01() 53 { 54 55 Parent p1; //3 动手脚 提前布局 56 //用类定义对象的时候 C++编译器会在对象中添加一个vptr指针 57 Child c1; //子类里面也有一个vptr指针 58 59 HowToPlay(&p1); 60 HowToPlay(&c1); 61 62 cout<<"hello..."<<endl; 63 system("pause"); 64 return ; 65 }