函数指针初识
- 函数指针指向的是函数而非对象。
- 和其他指针一样,函数指针指向某种特定类型。
- 函数的类型由它的返回类型和形参类型共同决定。
- 例如:
//比较两个string对象的长度
bool lengthCompare(const string& s1,const string& s2);
- 该函数的类型是
bool(const string&,const string&).
- 要想声明一个可以指向该函数的指针,只需要用指针替换函数名即可:
//pf指向一个函数,该函数的两个参数是const string的引用,返回值是bool类型
bool (*pf)(const string & , const string &);//未初始化
注意:pf两端的括号比不可少,如果不写,则pf是一个返回类型为bool指针的函数
函数指针的使用
- 当我们把函数名作为一个值使用时,该函数自动转换为指针。
pf = lengthCompare;//pf指向名为lengthCompare的函数
pf=&lengthCompare; //等价赋值语句:取地址符是可逆的
- 此外,我们还能直接使用指向函数的指针调用该函数,无须提前解引用指针:
bool b1 = pf("hello", "goodbye");//调用lengthCompare函数
bool b2 = (*pf)("hello", "goodbye");//一个等价的调用
bool b3 = lengthCompare("hello", "goodbye");//另一个等价调用
- 在指向不同函数类型的指针间不存在转换规则
- 我们可以将函数指针赋值为nullptr或者值为0的整形常量表达式,表示当前函数指针没有指向任何一个函数
bool lengthCompare(const string& s1, const string& s2)
{
cout <<s1<<" "<<s2<< endl;
return true;
}
string::size_type sumLength(const string&, const string&)
{
return 0;
}
bool cstringCompare(const char*, const char*)
{
return true;
}
pf = 0;//正确:pf不指向任何函数
pf = sumLength;//错误:返回类型不匹配
pf = cstringCompare;//错误:形参类型不匹配
pf = lengthCompare;//正确:函数和指针类型精确匹配
重载函数指针
- 当我们使用重载函数时,上下文必须精确地界定到底应该选用哪个函数。
void ff(int*)
{
cout << "ff(int*)" << endl;
}
void ff(unsigned int)
{
cout << "ff unsigned int" << endl;
}
void test()
{
void (*pf1)(unsigned int) = ff;//pf1指向ff(unsigned)
pf1(1);
}
- 编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中某一个精确匹配。
void (*pf2)(int) = ff;//错误:没有任何一个ff与该形参列表匹配
int (*pt3)(int*) = ff;//错误:没有任何一个ff与pt3的返回类型匹配
函数指针形参
- 虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。此时形参看起来是函数类型,实际上却是当做指针使用。
//比较两个string对象的长度
bool lengthCompare(const string& s1, const string& s2)
{
if(s1.size()>s2.size())
return true;
return false;
}
//第三个参数是函数类型,它会自动转换成指向函数的指针
bool useBigger(const string& s1, const string& s2, bool bf(const string& s1, const string& s2))
{
return bf(s1, s2);
}
void test()
{
string s1 = "abc";
string s2 = "abcdfe";
if (useBigger(s1, s2, lengthCompare))
{
cout << "s1大于s2" << endl;
}
else
cout << "s1小于s2" << endl;
}
//等价的声明:显示地将形参定义成指向函数的指针
bool useBigger(const string& s1, const string& s2, bool (*bf)(const string& s1, const string& s2))
{
return bf(s1, s2);
}
- 我们可以直接把函数作为实参使用,此时它会自动转换为指针
//自动将函数lengthCompare转换成指向该函数的指针
useBigger(s1, s2, lengthCompare);
//或者也可以用取地址符
useBigger(s1, s2, &lengthCompare);
- 类型别名和decltype能让我们简化使用了函数指针的代码:
//func和func2是函数类型
typedef bool func(const string&, const string&);
typedef decltype(lengthCompare) func2;//等价的类型
//funcp和funcp2是指向函数的指针
typedef bool(*funcp)(const string&, const string&);
typedef decltype(lengthCompare)* funcp2;//等价的类型
- 我们使用typefdef定义自己的类型,func和func2是函数类型,而funcp和funcp2是指针类型,需要注意的是,decltype返回函数类型,此时不会将函数类型自动转换为指针类型,因为decltype的结果是函数类型,所以只有在结果前面加上*才能得到指针。
- 可以使用如下形式重新声明useBigger:
//useBigger的等价声明,其中使用了类型别名
void useBigger(const string & s1, const string & s2, func);
void useBigger(const string & s1, const string & s2, func2);
void useBigger(const string & s1, const string & s2, funcp);
void useBigger(const string & s1, const string & s2, funcp2);
- 前两句等价声明中,编译器自动把func表示的函数转换为指针
返回值指向函数的指针
- 和数组类似,虽然不能返回一个函数,但是能返回指向函数类型的指针,
- 然而,我们必须把返回类型写成指针形式,编译器不会自动地将函数返回类型当初对应的指针类型处理
- 与前面一样,要想声明一个返回函数指针的函数,最简单的办法是使用类型别名:
using F = int(int*, int*);//F是函数类型,不是指针
using FF = int(*)(int*, int*);//FF是指针类型
注意:返回值不会自动地转换为指针,我们必须显示将返回类型指定为指针
FF f1(int);//正确:FF是指向函数的指针,f1返回指向函数的指针
F f2(int);//错误:F是函数类型,f1不能返回一个函数
F* f3(int);//正确:显示地指定返回类型是指向函数的指针
- 当然,我们也可以用下面形式直接声明f1:
int (*f1(int))(int*, int*);
-
按照由内向外的顺序阅读这条声明语句:我们看到f1有形参列表,所以f1是个函数;
-
f1前有*,所以f1返回一个指针;
-
进一步观察发现,指针的类型本身也包含形参列表,因此指针指向函数,该函数返回的类型是int.
-
举例说明:
int addSum(int* a, int* b)
{
cout << "a+b= " << *a + *b << endl;
return 1;
}
int (*f1(int val))(int*, int*)
{
addSum(&val, &val);
return addSum;
}
void test()
{
auto ret = f1(10);
}
将auto和decltype用于函数指针类型
- 如果我们明确知道返回的函数是哪一个,就能使用decltype简化书写函数指针返回类型的过程。
string::size_type a(const string& s1, const string& s2)
{
return s1.size() + s1.size();
}
string::size_type b(const string& s1)
{
return s1.size() + s1.size();
}
decltype(a) * getFunc(const string& s)
{
cout << "a(s,s)= " << a(s, s) << endl;
b(s);
return a;
}
void test()
{
auto ret = getFunc("abc");
cout << ret("abcd","casd") << endl;
//直接打印函数名,或解引用的效果一样,得到的都是函数的地址
cout << ret<< endl;
cout << *ret<< endl;
}
点个赞,再走吧,个位亲
转载:https://blog.csdn.net/m0_53157173/article/details/116266434
查看评论