-1

我正在学习函数指针并遇到以下代码:

#include <iostream>
using namespace std;

// A macro to define dummy functions:
#define DF(N) void N() { \
    cout << "function " #N " called ... " << endl; }

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

void (*func_table[])() = {a, b, c, d, e, f, g}; 

int main(){
    while(1){
        cout << "press a key from 'a' to 'g' " 
        "or q to quit"<< endl;
        char c, cr;
        cin.get(c); cin.get(cr); // second one for CR
        if ( c == 'q')
        break;
        if (c < 'a' || c > 'g')
        continue;
        (*func_table[c-'a'])();
    }
}

有人可以向我解释指向函数 func_table 的指针是如何工作的吗?特别是在里面有 a,b,c,d,e,f,g 的效果是{}什么以及整个表达式在做什么?

通常,当我看到指向函数的指针时,您会通过分配函数名称来初始化指针,但在此示例中,它只是提供了一个字符数组。那么它是如何知道调用 DF(char) 的呢?

另外,我不确定为什么我需要这些陈述:

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

此外,声明:(*func_table[c-'a'])(); 我们减去“a”的原因是因为不同将确定从数组中选择的正确字母{a,b,c,d,e,f,g}

4

4 回答 4

1

那是一些丑陋的,混淆的代码,它让你感到困惑并不可惜。让我们一块一块地做:

// A macro to define dummy functions:
#define DF(N) void N() { \
    cout << "function " #N " called ... " << endl; }

DF(a); 

如果您扩展该宏调用,您将获得:

void a() { 
    cout << "function a called ... " << endl; }

与 b、c 等类似。所以a通过g打印自己的名字的函数,仅此而已。

void (*func_table[])() = {a, b, c, d, e, f, g}; 

使用 typedef 更容易阅读:

typedef void (*FuncPtr)(); //FuncPtr is a function pointer to functions of type void X();
FuncPtr func_table[] = {a, b, c, d, e, f, g};

实际上,也就是说{&a, &b, &c, &d, &e, &f, &g}- 作者利用了隐式函数到函数指针的转换。含义:是一个指向通过func_table的函数指针数组ag

int main(){
    while(1){
        cout << "press a key from 'a' to 'g' " 
        "or q to quit"<< endl;
        char c, cr;
        cin.get(c); cin.get(cr); // second one for CR
        if ( c == 'q')
        break;
        if (c < 'a' || c > 'g')
        continue;

这应该很清楚。现在调用:

    (*func_table[c-'a'])();

c-'a'是从 的偏移量'a',表示“a”为 0,“b”为 1,依此类推。例如,如果 c 是 'd',则此行调用(*func_table['d'-'a'])(), wich is *(func_table[3])()wich is just d- 因此该行仅调用您刚刚键入的名称的函数。

于 2013-07-15T08:12:37.247 回答
0

这一行:

#define DF(N) void N() { \
    cout << "function " #N " called ... " << endl; }

定义了一个名为 的新函数N。这是可行的,因为宏只是创建了一个文本替换,所以当编译器看到它时,它会看到一个完全有效的函数,名称N为 ,就好像你输入了函数一样

 void a() {\... }

这里有用上述宏声明的函数,命名为a-g

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

这里:

void (*func_table[])() = {a, b, c, d, e, f, g}; 

上面声明的函数只是简单地赋值。

减去字符的原因是在函数数组中获取索引 0-n。

于 2013-07-15T08:01:38.747 回答
0

通常,当我看到指向函数的指针时,您会通过分配函数名称来初始化指针,但在此示例中,它只是提供了一个字符数组。那么它是如何知道调用 DF(char) 的呢?

实际上,它不是给定一个字符数组,而是一个函数数组。DF(a)将定义一个函数命名a

所以基本上,你最终有一个函数指针数组指向你的函数(即,,,,... a)。bc

我们减去'a'的原因是,如果用户按下b键,我们将要调用该b函数。您的变量c将具有“b”作为值。'b' - 'a' = 1。因此它将调用数组的第二个函数指针(因为 array[1] 是第二个元素),这实际上是函数 nammed b

于 2013-07-15T08:02:15.673 回答
0

丑丑...

DF(N)创建一个输出“N”的 N 函数(在宏中使用 # 运算符)

所以:

 DF(a);

是一种更短的书写方式

 void a(){cout << "function Acalled" << endl;}

现在它们存储在一个数组中:

func_table[0]() 

相当于

a()

使用字符c-'a'会在两个字符之间产生差异:'a' - 'a' = 0

然后调用func_tables[c-'a']将调用预期的函数。

于 2013-07-15T08:05:16.150 回答