C/C++ 函数指针
2018-12-29 本文已影响111人
落雪1117
首先需要明确,指针指向的是某种特定类型,而函数的类型由其参数及返回类型共同决定,与函数名无关。
函数声明:
int add(int, int);
所对应的类型为int(int, int)
,指向该类函数的指针可以声明为:
int (*pf)(int, int);
即使用指针替换函数名。这样,pf可指向int(int, int)
类型的函数。
pf前面有*,说明pf是指针;右侧是形参列表,表示pf指向的是函数;左侧为int,说明pf指向的函数返回值类型为int。即pf可指向int(int, int)
类型的函数:
pf = add;
这样通过赋值可以使得函数指针指向某具体函数。
⚠️:*pf两端的括号必不可少
int *pf(int, int);
此时声明一个名为pf返回类型为int指针的函数。
C的函数指针
1 - 定义###
// 1.一般定义
int (*pf)(int, int);
// 2.使用typedef定义
typedef int (*PF)(int, int);
PF pf;
2 - 普通使用方法
pf = add; // 指向具体函数
pf(100, 100); // 与指向函数的用法无异
(*pf)(100, 100); // 此时*pf两端括号必不可少
3 - 作为形参
// 1.若形参为函数类型,会自动转换为指向此类函数的指针
void func(int value, int pf(int, int));
// 2.将形参显式定义为指向函数的指针
void func(int value, int (*pf)(int, int));
typedef int (*PF)(int, int);
void func(int value, PF);
4 - 作为返回值
// 1.使用typedef定义的函数指针类型作为返回参数
typedef int (*PF)(int, int);
PF func(int);
// 2.直接定义函数指针作为返回参数
int (*func(int))(int, int);
按照由内向外的顺序理解此声明语句。
*func有形参列表,则func是一个函数,且其形参列表为(int)
;
*func前面有*,所以func返回一个指针;
*指针本身也包含形参列表(int,int)
,因此指针指向函数,且该函数的返回值为int。
即:func是一个函数,形参为(int),返回一个指向int(int, int)类型的函数指针。
C++的函数指针
C中可用的函数指针用法皆可用于C++。
1 - C++11中的函数指针声明
decltype(add) *pf;
decltype
返回函数的类型,具体参见C++11中关于decltype的使用方法。
可将typedef
与decltype
组合定义函数指针:
// 1.直接定义指针类型
typedef decltype(add) *PF;
PF pf;
// 2.定义函数类型别名
typedef decltype(add) anotherAdd;
anotherAdd *pf;
使用auto
推断类型:
// 1.pf可认为是add的别名
auto pf = add;
// 2.pf为指向add的指针
auto *pf = add;
2 - 作为形参
// 1.函数类型作为形参自动转换为函数指针
typedef decltype(add) anotherAdd;
void func (anotherAdd add);
// 2.直接传入函数指针
typedef decltype(add) *PF;
void func (PF add);
3 - 作为返回值
// 1.使用auto
auto func(int) -> int(*)(int, int) // C++11
auto func(int) // C++14
// 2.使用decltype
decltype(add) *func(int)
4 - 在类中使用函数指针
class Hoge {
private:
int add(int val1, int val2) {
return val1 + val2;
}
public:
void sayHello() {
std::cout << "Hello!" << std::endl;
}
};
typedef void(Hoge::*sayHelloP)(); // 指针名前加上类名限定
int main() {
sayHelloP pf = &Hoge::sayHello; // 注意'&'
Hoge hoge; // 成员函数地址解引用必须在对象上
(hoge.*pf)(); // 使用成员函数指针调用函数
return 0;
}
5 - 在类继承中使用
class Hoge {
public:
void func() {
std::cout << "Hello, func!" << std::endl;
}
void func2() {
std::cout << "Hello, Hoge::func2!" << std::endl;
}
};
class Piyo: public Hoge {
public:
void func2() {
std::cout << "Hello, Piyo::func2!" << std::endl;
}
};
typedef void(Hoge::*HogePF)();
typedef void(Piyo::*PiyoPF)();
int main() {
Hoge hoge;
Piyo piyo;
HogePF hoge_pf = &Hoge::func;
(hoge.*hoge_pf)(); // --> "Hello, func!"
(piyo.*hoge_pf)(); // --> "Hello, func!"
hoge_pf = &Hoge::func2;
(hoge.*hoge_pf)(); // --> "Hello, Hoge::func2!"
(piyo.*hoge_pf)(); // --> "Hello, Hoge::func2!"
PiyoPF piyo_pf = &Hoge::func2;
//(hoge.*piyo_pf)(); --> ERROR
(piyo.*piyo_pf)(); // --> "Hello, Hoge::func2!"
piyo_pf = &Piyo::func2;
//(hoge.*piyo_pf)(); --> ERROR
(piyo.*piyo_pf)(); // --> "Hello, Piyo::func2!"
return 0;
}
6 在函数重载中使用
编译器通过指针类型决定选取那个函数,指针类型必须与重载函数中的一个精确匹配:
void func();
void func(int);
void (*PF)(int) = func; // PF指向void fuc(int);
//int (*PF2)(int) = func; // 错误!没有匹配的类型