CON TRỎ HÀM (FUNCTION POINTER)
Tải về: tại đây [DOC]
Nguồn tham khảo: http://www.newty.de/fpt/index.html, Ngôn ngữ lập trình C++
I. Giới thiệu Function Pointer
Khi một chương trình chạy sẽ chiếm một vùng nhớ xác định trong bộ nhớ chính, cả đoạn chương trình và các biến sử dụng đều được đưa vào vùng nhớ này. Vì vậy một function trong chương trình của bạn luôn có một địa chỉ xác định trong bộ nhớ. Function pointer là một pointer mà nó chỉ đếnđịa chỉ của một hàm.
II. Sử dụng Function Pointer
2.1 Khai báo
Con trỏ hàm được khai báo tương tự như khai báo nguyên mẫu hàm thông thường trong C++, ngoại trừ việc có thêm kí hiệu con trỏ “*” trước tên hàm. Cú pháp khai báo con trỏ hàm như sau:
<Kiểu dữ liệu trả về> (*<Tên hàm>)([<Các tham số>]);
Trong đó:
Kiểu dữ liệu trả về: là các kiểu dữ liệu thông thường của C++ hoặc kiểu do người dùng tự định nghĩa.
Tên hàm: tên do người dùng tự định nghĩa, tuân thủ theo quy tắc đặt tên biến trong C++.
Các tham số: có thể có hoặc không. Nếu có nhiều tham số, mỗi tham số được phân cách nhau bởi dấu phẩy.
Ví dụ:
int (*p) (float);
thì p là một con trỏ hàm trả về kiểu int, có một tham số hàm kiểu float.
void (*p2) (int*, int) ;
thì p2 là một con trỏ hàm trả không có kiểu trả về (void), có một tham số kiểu int* và một tham số kiểu int
Lưu ý:
Dấu “()” bao bọc tên hàm là cần thiết để chỉ ra rằng ta đang khai báo một con trỏ hàm. Nếu không có dấu ngoặc đơn này, trình biên dịch sẽ hiểu rằng ta đang khai báo một hàm thông thường và có giá trị trả về là một con trỏ. Ví dụ, hai khai báo sau là khác nhau hoàn toàn:
// Khai báo một con trỏ hàm:
int (*p) (float);
// Khai báo một hàm trả về kiểu con trỏ:
int *p (float);
2.2 Sử dụng
2.2.1 Gán một địa chỉ vào con trỏ hàm và gọi hàm qua con trỏ hàm
Chỉ cần lấy tên của một hàm thích hợp và gán vào con trỏ hàm. Hàm và con trỏ hàm phải có khuôn mẫu (các tham số) giống nhau.
Ví dụ:
Ta có hàm:
float add(float a, float b){
return a+b;
}
|
Và có con trỏ hàm:
float (*p)(float, float); |
Thì ta có thể thực hiện phép gán:
p = add; //Dạng rút gọnhoặc
p = &add; //Dạng đầy đủ với toán tử lấy địa chỉ &
|
Phép gán bên dưới là không thể vì hàm và con trỏ hàm không cùng khuôn mẫu
float (*p)(float, int);p = &add; |
Ghi chú: Mặc dù hầu hết các trình biên dịch cho phép viết theo kiểu rút gọn nhưng chúng ta nên sử dụng toán tử địa chỉ (&) đặt trước tên hàm đểthể hiện đúng ý nghĩa việc gán một địa chỉ vào một con trỏ hàm.
Sau khi thực hiện phép gán địa chỉ của add cho con trỏ p thì ta có thể gọi hàm add thông qua p
float t = p (1, 2);hoặc
float t = (*p) (1, 2);
|
Một số ví dụ khác:
Khai báo con trỏ hàm
|
Hàm
|
Sử dụng
|
int (*p) (float) | int Round(float x) | p = &Round;p (1.5F); |
void (*p) (int*, int) | void Sort( int *a, int n) | int a[] = {1, 2, -1};p = &Sort;
p(a,sizeof(a)/sizeof(int));
|
float (*p)() | float Random() | p = &Random;float t = p(); |
2.2.2 Định nghĩa kiểu dữ liệu con trỏ hàm
typedef <Kiểu trả về> (*<Tên kiểu dữ liệu>) (<Tham số>)
Ví dụ:
typedef float(*pt2Func)(float, float); //Định nghĩa kiểu pt2Funcpt2Func p; //Khai báo biến p có kiểu pt2Func là kiểu con trỏ hàm |
2.2.3 So sánh các con trỏ hàm
Chúng ta có thể sử dụng các toán tử so sánh (==, !=, <, >) như bình thường.
Ví dụ:
typedef float(*pt2Func)(float, float); //Định nghĩa kiểu pt2Funcpt2Func p; //Khai báo biến p có kiểu pt2Func là kiểu con trỏ hàm
p = + //Gán địa chỉ hàm add cho p
if (p > 0)//Kiểm tra con trỏ hàm có chứa địa chỉ trỏ đến hay không
{
if (p == &plus) //Kiểm tra địa chỉ p trỏ đến có bằng địa chỉ hàm sub hay không
cout<<”p tro den ham plus”;
}
else
cout<<”Chua co dia chi tro den!”;
|
2.2.4 Truyền con trỏ hàm như là một tham số
Chúng ta có thể truyền function pointer như một tham số của một function được gọi khác.
Ví dụ: truyền con trỏ hàm thực hiện phép tính cộng hoặc trừ
#include <iostream>using namespace std;
typedef float(*pt2Func)(float, float); //Định nghĩa kiểu pt2Func
float add (float a, float b)
{
return (a+b);
}
float sub (float a, float b)
{
return (a-b);
}
float operation (float x, float y, pt2Func p) //Tham số p có kiểu pt2Func
//tương đương với: float operation (float x, float y, float(*p)(float, float))
{
return p (x, y);//Gọi hàm thông qua con trỏ p
}
void main ()
{
float m,n;
pt2Func pt = sub;
m = operation (7, 5, add); //Truyền địa chỉ hàm add
n = operation (20, m, pt); //Truyền con trỏ hàm pt
cout<<n;
}
|
Ví dụ: Sử dụng quick sort bằng hàm qsort của thư viện stdlib.h
#include “stdio.h”#include “stdlib.h”
int compare_int1 (const void *a , const void *b)
{
return *(int*)a < *(int*)b;
}
int compare_int2 (const void *a , const void *b)
{
return *(int*)a > *(int*)b;
}
void main()
{
int a[] = {1, 6, 9, -1, 0};
int n = sizeof(a)/sizeof(int);
qsort(a, n, sizeof(int), &compare_int1); //Sắp xếp tăng
for (int i = 0; i < n; i++)
printf(“%d “,a[i]);
printf(“n”);
qsort(a, n, sizeof(int), &compare_int2); //Sắp xếp giảm
for (int i = 0; i < n; i++)
printf(“%d “,a[i]);
}
|
2.2.5 Hàm trả về một con trỏ hàm
Một function pointer có thể là giá trị trả về của một function
Ví dụ:
#include <iostream>using namespace std;
typedef float(*pt2Func)(float, float); //Định nghĩa kiểu pt2Func
float add (float a, float b)
{
return (a+b);
}
float sub (float a, float b)
{
return (a-b);
}
pt2Func GetFunc (char op) //Hàm GetFunc trả về kiểu pt2Funct là một con trỏ hàm
//tương đương với float (*GetFunc(char op))(float, float)
{
if (op==’+')
return add;
else
return sub;
}
void main ()
{
float m = GetFunc(‘-’)(4,2);
cout<<m;
}
|
2.2.6 Sử dụng mảng các con trỏ hàm
Sử dụng một mảng các con trỏ hàm khá thú vị, nó cho phép lựa chọn một hàm thông qua chỉ số, đây là cách thay thế cho biểu thức điều kiện hay cấu trúc điều kiện.
Ví dụ: Chương trình nhập vào 2 số a, b và phép tính p (+, -, *, /), tính và đưa ra kết quả với ràng buộc không cấu trúc điều kiện hay biểu thức điều kiện.
#include <iostream>using namespace std;
typedef float(*pt2Func)(float, float); //Định nghĩa kiểu pt2Func
float add (float a, float b)
{
return (a+b);
}
float sub (float a, float b)
{
return (a-b);
}
float mul (float a, float b)
{
return (a*b);
}
float div (float a, float b)
{
return (a/b);
}
void main ()
{
float a, b;
char ch;
pt2Func op[256] = {0};//Mảng 256 con trỏ hàm pt2Func
//tương đương với khai báo float (* op[256])(float, float);
op['+'] = add;
op['-'] = sub;
op['*'] = mul;
op['/'] = div;
cout<<” a = “;
cin>>a;
cout<<” b = “;
cin>>b;
cout<<”Phep tinh: “;
cin>>ch;
cout<<”Ket qua: “<<op[ch](a,b);
}
|
0 nhận xét