سؤال

أريد إنشاء دالة يؤدي وظيفة مرت من قبل المعلمة على مجموعة من البيانات.كيف يمكنك تمرير وظيفة كمعلمة في C ؟

هل كانت مفيدة؟

المحلول

إعلان

نموذج دالة التي تأخذ وظيفة معلمة تبدو كما يلي:

void func ( void (*f)(int) );

هذه الدول التي المعلمة f سوف يكون مؤشر على وظيفة التي لديه void عودة النوع الذي يأخذ واحد int معلمة.الدالة التالية (print) هو مثال على وظيفة التي يمكن تمريرها إلى func كمعلمة لأنه هو النوع المناسب:

void print ( int x ) {
  printf("%d\n", x);
}

استدعاء دالة

عند استدعاء الدالة مع دالة المعلمة القيمة التي تم تمريرها يجب أن يكون مؤشر على وظيفة.استخدام وظيفة اسم (بدون قوسين) على هذا:

func(print);

سيدعو func, تمرير وظيفة الطباعة إلى ذلك.

وظيفة الجسم

كما هو الحال مع أي معلمة, func يمكن الآن استخدام المعلمة اسم في وظيفة الجسم للوصول إلى قيمة المعلمة.دعنا نقول أن ظائفها سيتم تطبيق الدالة يتم تمرير إلى أرقام 0-4.تنظر أول ما الحلقة تبدو الاتصال الطباعة مباشرة:

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

منذ func's المعلمة الإعلان يقول أن f هو اسم مؤشر إلى الوظيفة المطلوبة ، نذكر أولا أنه إذا f هو مؤشر ثم *f هو الشيء الذي f نقطة (أيوظيفة print في هذه الحالة).ونتيجة لذلك, مجرد استبدال كل حدوث الطباعة في حلقة أعلاه مع *f:

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

من http://math.hws.edu/bridgeman/courses/331/f05/handouts/c-c++-notes.html

نصائح أخرى

هذا السؤال وقد سبق الجواب عن تحديد مؤشرات الدالة ، ومع ذلك فإنها يمكن أن تحصل فوضوي جدا, خاصة إذا كنت تنوي أن يمر عليها حول التطبيق الخاص بك.لتجنب هذا البغض وأود أن ننصح typedef وظيفة المؤشر إلى شيء أكثر قابلية للقراءة.على سبيل المثال.

typedef void (*functiontype)();

تعلن الدالة التي ترجع باطل لا يأخذ الحجج.لإنشاء وظيفة مؤشر إلى هذا النوع يمكنك القيام به الآن:

void dosomething() { }

functiontype func = &dosomething;
func();

عن الدالة التي ترجع الباحث ويأخذ شار كنت تفعل

typedef int (*functiontype2)(char);

واستخدامها

int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');

هناك المكتبات التي يمكن أن تساعد في تحول مؤشرات الدالة إلى لطيفة للقراءة أنواع.على تعزيز وظيفة مكتبة كبيرة و جيد يستحق كل هذا الجهد!

boost::function<int (char a)> functiontype2;

هو أجمل بكثير مما سبق.

منذ C++11 يمكنك استخدام وظيفية المكتبة للقيام بذلك في محكم عام.بناء الجملة هو ، على سبيل المثال ،

std::function<bool (int)>

حيث bool هو عودة اكتب هنا مرة واحدة الحجة الدالة الذين الحجة الأولى هي من نوع int.

ولقد تضمنت على سبيل المثال البرنامج أدناه:

// g++ test.cpp --std=c++11
#include <functional>

double Combiner(double a, double b, std::function<double (double,double)> func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

في بعض الأحيان, على الرغم من أنه هو أكثر ملاءمة لاستخدام قالب الوظيفة:

// g++ test.cpp --std=c++11

template<class T>
double Combiner(double a, double b, T func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

تمر عنوان وظيفة المعلمة إلى وظيفة أخرى كما هو مبين أدناه

#include <stdio.h>

void print();
void execute(void());

int main()
{
    execute(print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void f()) // receive address of print
{
    f();
}

كما يمكننا تمرير وظيفة المعلمة باستخدام وظيفة مؤشر

#include <stdio.h>

void print();
void execute(void (*f)());

int main()
{
    execute(&print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void (*f)()) // receive address of print
{
    f();
}

تحتاج إلى تمرير وظيفة مؤشر.بناء الجملة هو مرهقة قليلا, لكنه قوي حقا مرة واحدة يمكنك الحصول على دراية به.

وظائف يمكن "تمريرها" كما مؤشرات الدالة كما في 6.7.6.3p8:"إعلان المعلمة "وظيفة عودته من نوع" تعدل إلى "مؤشر إلى وظيفة عودته نوع" ، كما في 6.3.2.1. ".على سبيل المثال هذا:

void foo(int bar(int, int));

يعادل هذا:

void foo(int (*bar)(int, int));

انها ليست حقا وظيفة, بل هو الموطن قطعة من التعليمات البرمجية.وبطبيعة الحال فإنه لا يمر رمز فقط نتيجة.فهو لن يعمل إذا مرت على الحدث المرسل ليتم تشغيلها في وقت لاحق (نتيجة يحسب الآن وليس عند حدوث الحدث).لكنه لا توطين التعليمات البرمجية الخاصة بك في مكان واحد إذا كان هذا هو كل ما كنت تحاول القيام به.

#include <stdio.h>

int IncMultInt(int a, int b)
{
    a++;
    return a * b;
}

int main(int argc, char *argv[])

{
    int a = 5;
    int b = 7;

    printf("%d * %d = %d\n", a, b, IncMultInt(a, b));

    b = 9;

    // Create some local code with it's own local variable
    printf("%d * %d = %d\n", a, b,  ( { int _a = a+1; _a * b; } ) );

    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top