-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 などについても同様です。したがってag関数は独自の名前を出力するだけで、それ以上のものはありません。

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. したがって、配列の 2 番目の関数ポインターが呼び出されます (array[1] は 2 番目の要素であるため)。これは、実際には関数 nammedbです。

于 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'すると、2 つの文字に違いが生じます。'a' - 'a' = 0

呼び出しfunc_tables[c-'a']は、期待される関数を呼び出します。

于 2013-07-15T08:05:16.150 に答える