Function Pointer

今天才知道各各系统的man是不一样的,mac下查man还是上网查把。

0.前言 C实现virtual function

1
2
3
4
5
6
7
8
函数:
{返回值类型} {函数名}({参数列表})这个格式你应该很熟悉了,就是函数

函数指针:函数指针也是一种变量,可以直接以函数名赋值
{返回值类型} (*{变量名})({参数列表})

变量声明:
{类型} {和表达式很像的东西}

1.基础应用(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef float (*pf) (float, float);
//pf 是函数指针类型,注意此处*的位置,表示取值
//typedef 将pf变成一个类型
//如果没有typedef,需要对每个同样函数指针的定义做相同的事情
//float (*pf)(float, float);
//float (*a)(float, float);
//此处变量名也可以省去,方便YY :)

float foo(flaot a, float b) {
  return 0;
}

int main() {
  pf a = &foo;
  (*a)(1,1);
}

2.基础应用(2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef int (*fp)(int, int);

int add (int a, int b) {
    return a+b;
}

int imp(int a, int b, fp f) {
    return (*f)(a,b);
}

int main () {
    printf("result is %i", imp(1,1,add));
        return 0;
}

3.两种定义形式

  • C: 返回类型 (*函数指针名称)(参数类型,参数类型,参数类型,…);
  • C++: 返回类型 (类名称::*函数成员名称)(参数类型,参数类型,参数类型,…);

4.函数指针作为返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int (*foo(char op))(int a, int b) {
  if(op == '+') {
      return add;
  }else {
      return 0;
  }
}

void (*signal)(int signo,void (*func)(int))(int);
//unix 系统函数
//函数名称signal
//接受两个参数- int 和 一个函数指针
//返回函数指针类型为: void(*)(int)
//照着读signal 调用两次以后返回void

int main () {
  int (*returnpf)(int a, int b); // (*returnpf) 这个括号不能少
  returnpf = foo('+');
  printf("result is %i\n", (*returnpf)(1,3));
  //or
  printf("result is %i\n", foo('+')(1,1));
}

5.函数指针数组

1
float (*pFunctionArray[10])(float, float);

6.用typedef 简化函数

1
2
3
4
5
6
7
typedef void (*pf)(int);
//void (*signal)(int signo,void (*func)(int))(int);
//= pf signal(int signo, pf func);

typedef void pf(int);
//void (*signal)(int signo,void (*func)(int))(int);
// = pf* signal(int signo, pf* func);

7.附言,米米的教导 米米知乎解答

1
2
3
4
5
6
7
8
int (*signal[4])(int)(char)[6];
//变量申明
//该表达式返回int
//所以(*signal[4])(int)(char)返回一个int指针(可以用作[6])
//(*signal[4])(int)是一个函数指针,接受参数char,返回int指针
//signal[4]是一个函数指针,接受int,返回另一个函数指针,后者的函数类型如上所述,“接受char,返回int指针”
//现在signal是啥呢,肯定是个数组。什么数组呢?上一条那玩意的数组
//结论:signal是一个函数指针数组,函数指针的函数类型为:接受int,返回另一个函数指针,后者的函数类型为“接受char,返回int指针”

8.如何使用function pointer 实现dynamic dispatch?

原理非常简单就是在初始化时候将内部的function pointer,指向implementation的真实function从而达到目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void funA_imp() { printf("world"); }

void funBase_imp() { printf("hello"); }

struct Base { void (*fun)(); };

struct A { void (*fun)(); };

int main() {
    struct Base b;
    // dynamic dispatch
    // struct A a;
    // a.fun = &funA_imp;
    // b.fun = a.fun;
    b.fun = &funBase_imp;
    b.fun();
}

virtual function 也是同理

Base class maintain 一个__vptr* 指向真实的vtable (array of functions) implementation,而所有的derived class 包括 base 自己都有一个 vtable 的implementation.

下面 class A in c++:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {
protected:
    int a;
public:
    A() {a = 10;}
    virtual void update() {a++;}
    int access() {update(); return a;}
};

class B {
  public:
      void update() {a--;}
};

可以用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
struct A;

typedef struct {
    void (*A)(struct A*);
    void (*update)(struct A*);
    int (*access)(struct A*);
} A_functable;

typedef struct A{
    int a;
    A_functable *vmt;
} A;

void A_A(A *this);
void A_update(A* this);
int A_access(A* this);

A_functable A_vmt = {A_A, A_update, A_access};

void A_A(A *this) {this->vmt = &A_vmt; this->a = 10;}
void A_update(A* this) {this->a++;}
int A_access(A* this) {this->vmt->update(this); return this->a;}

/*
class B: public A {
public:
    void update() {a--;}
};
*/

struct B;

typedef struct {
    void (*B)(struct B*);
    void (*update)(struct B*);
    int (*access)(struct A*);
} B_functable;

typedef struct B {
    A inherited;
} B;

void B_B(B *this);
void B_update(B* this);

B_functable B_vmt = {B_B, B_update, A_access};

void B_B(B *this) {A_A(this); this->inherited.vmt = &B_vmt; }
void B_update(B* this) {this->inherited.a--;}
int B_access(B* this) {this->inherited.vmt->update(this); return this->inherited.a;}

int main() {
    A x;
    B y;
    A_A(&x);
    B_B(&y);
    printf("%d\n", x.vmt->access(&x));
    printf("%d\n", y.inherited.vmt->access(&y));
}