函数的类型与地址
我们来看下面这个典型的函数:
int foo()
{
return 5;
}
显然foo 是函数名,而int是函数返回值的类型。但是,函数有类型吗?有,函数有自己的类型,比如上面这个函数的类型即为“无参数且返回类型为整型”的函数。我们可以这么表示这种类型int (*somefunction)(),同样的,如果是“有两个整形参数且返回值是布尔型”的我们可以这么表示bool (someotherfunction)(int, int)
有人认为这个不属于函数的类型,其实吧我只是觉着这么解释容易理解,你当然也可以不这么想。
和变量一样,函数在内存中有固定的地址。函数的实质也是内存中一块固定的空间。
比如,当我这样调用函数foo():
cout << reinterpret_cast<void>(foo);
或者这样:
std::cout<<foo; //在我的机器上打印出来的是数字1,而不是地址,
// 也有说是true的。
// 如果你用python,直接打印函数名(不带括号),出来的肯定是地址
结果是内存中的一个地址:0x103f87e20(具体取决于你的编译器)
函数指针
对于变量我们可以用int *a这样的语法创建一个指针,如果我们想写一个指向函数的指针我们可以这么写:
int(*funcPtr)(); //funcPtr is short for ‘function pointer’/函数指针
//或者我们也可以这么写,如果你需要一个静态的函数指针
int (*const funcPtr)();
另外,对于 const int(*funcPtr),意思是这个指针指向的函数的返回值是常量
把一个函数赋值给函数指针
int foo()
{
return 5;
}
int goo()
{
return 6;
}
int main()
{
int (*funcPtr)() = foo; // funcPtr 现在指向了函数foo
funcPtr = goo; // funcPtr 现在又指向了函数goo
//但是千万不要写成funcPtr = goo();这是把goo的返回值赋值给了funcPtr
return 0;
}
再来一波函数练习一下
int foo();
double goo();
int hoo(int x);
// 给函数指针赋值
int (*funcPtr1)() = foo; // 可以
int (*funcPtr2)() = goo; // 错误!返回值不匹配!
double (*funcPtr4)() = goo; // 可以
funcPtr1 = hoo; // 错误,因为参数不匹配,funcPtr1只能指向不含参数的函数,而hoo含有int型的参数
int (*funcPtr3)(int) = hoo; // 可以,所以应该这么写
另外,可以这么写
int foo(){
return 5;
}
int main()
{
int (*funcPtr1)() = foo;
int (*funcPtr2)() = &foo; // c++会隐式得把foo转换成&foo,所以你无需再加入&
std::cout << funcPtr1() << std::endl;
std::cout << funcPtr2() << std::endl;
}
结果:
5
5
通过函数指针调用函数
int foo(int x)
{
return x;
}
int main()
{
int (*funcPtr)(int) = foo;
(*funcPtr)(5); // 通过funcPtr调用foo(5)
funcPtr(5) // 也可以这么使用,在一些古老的编译器上可能不行
return 0;
}
把函数作为参数传入另一个函数
第一个栗子
#include <iostream>
int add(int a, int b){
return a+b;
}
int sub(int a, int b){
return a-b;
}
void func(int e, int d, int(*f)(int a, int b)){ // 这里才是我想说的,
// 传入了一个int型,双参数,返回值为int的函数
std::cout<<f(e,d)<<std::endl;
}
int main()
{
func(2,3,add);
func(2,3,sub);
return 0;
}
第二个栗子
首先我们来看这个简单的冒泡排序
我们用ascending和descending两个函数代替大小判断,这样在调用的时候就可以选择是升序或者降序排列了
#include <iostream>
template <typename T>
bool ascending(T x, T y) {
return x > y;
}
template <typename T>
bool descending(T x, T y) {
return x < y;
}
template<typename T>
void bubblesort(T *a, int n, bool(*cmpfunc)(T, T)){
bool sorted = false;
while(!sorted){
sorted = true;
for (int i=0; i<n-1; i++)
if (cmpfunc(a[i], a[i+1])) {
std::swap(a[i], a[i+1]);
sorted = false;
}
n--;
}
}
int main()
{
int a[8] = {5,2,5,7,1,-3,99,56};
int b[8] = {5,2,5,7,1,-3,99,56};
bubblesort<int>(a, 8, ascending);
for (auto e:a) std::cout << e << " ";
std::cout << std::endl;
bubblesort<int>(b, 8, descending);
for (auto e:b) std::cout << e << " ";
return 0;
}
// -3 1 2 5 5 7 56 99
// 99 56 7 5 5 2 1 -3 [Finished in 0.4s]
设置默认函数
void bubblesort(T *a, int n, bool(*cmpfunc)(T, T) = ascending)
完。