看到这个标题你可能会觉得很奇怪,函数声明谁不会啊?划走吧。
且慢,看了这篇文章,你也许会怀疑学了假的C++。
我们都知道,一个函数要在调用它之前的位置声明:
void func(); //函数声明
int main(){
func(); //调用函数
}
void fun(){ //函数定义
//do something
}
对于单文件程序来说,如果函数在调用它的位置前定义,可以不用声明:
void func(){ //函数定义
//do something
}
int main(){
func(); //调用函数
}
如果返回值类型相同,你可以在一行内声明多个函数:
double func1(double, double), func2(int);
甚至还能一边定义变量一边声明函数:
double var1, func(double);
不过要注意的是,声明的函数的返回值类型是否为指针或引用,并不是看最前面的基本数据类型是否有*或&,比如:
double *var1, func1(), *func2();
func1的返回值类型是double,而不是double*。func2的返回值类型才是double*
这不小菜一碟?接下来上主菜:
我们都知道,C++函数指针是这样写的:
int main(){
double (*func)(double, double);
}
变量func指向一类返回值类型为double,且有两个double类型的形参的函数。
那么,如果这样写会怎么样呢?
int main(){
double func1(double, double);
double *func2(double, double);
}
第一眼看上去好像还是函数指针,特别是func2,但仔细看,这不是函数的声明吗?咋就把它写到主函数内了呢?
其实是这样的,函数的声明既可以写到函数外,也可以写到函数内。如果在main函数内声明,则被声明的函数在被定义前只在main函数内起作用:
int main(){
double *func(double, double); //函数声明
double *value = func(0.5, 1.5); //函数调用
}
void test(){
func(1, 2); //错误,函数func未定义
}
double *func(double a, double b){ //函数定义
...
}
要不我们再把函数的声明放在更奇怪的位置上?
double invoke(double f(double, double), double a, double b){
return f(a, b);
}
好家伙,现在还把函数声明放在函数的形参上了。
当然这是合法的。为了调用这个函数,我们可以给他符合的函数做实参:
double add(double a, double b){
return a + b;
}
int main(){
double res = invoke(add, 0.5, 1.5);
}
我们常用typedef给函数指针类型起别名:
typedef double (*func)(double, double);
func f;
但如果:
typedef double func(double, double);
则是:定义一种类型func,可以用于声明 某种返回值类型为double,形参为两个double 的函数
同理,我们就可以把上面一系列代码写为:
typedef double func(double, double);
double invoke(func f, double a, double b){
return f(a, b);
}
double add(double a, double b){
return a + b;
}
int main(){
double res = invoke(add, 0.5, 1.5);
}
上面的代码还不足以说明func是 某种函数的声明 的类型,下面举另外一个例子:
typedef double d_dd(double, double);
d_dd add; //声明函数add
d_dd multiply; //声明函数multiply
int main(){
std::cout << add(0.5, 1.5) << std::endl;
std::cout << multiply(0.5, 1.5) << std::endl;
}
double add(double a, double b){ //定义函数add
return a + b;
}
double multiply(double a, double b){ //定义函数multiply
return a * b;
}
可以看到,d_dd add;
指的是double add(double, double);
,d_dd multiply
同理,使用d_dd
可以用来声明多个同返回值、同类型形参的函数。
在C++11之后,可以使用using
来替代typedef
,同理:
using d_dd = double(double, double);
d_dd add, multiply; //声明两个函数
这里回答一下封面图各行代码的意义:
double func;
:定义一个double类型的变量funcdouble func();
:声明一个返回值类型为double,无形参的函数funcdouble *func();
:声明一个返回值类型为double*,无形参的函数funcdouble (*func)();
:定义一个函数指针func,可以指向一类返回值类型为double,无形参的函数typedef double func;
:定义一种类型func,原型为double。typedef double func();
:定义一种类型func,可以用来声明 某个返回值类型为double,无形参 的函数。typedef double (*func)();
:定义一种类型func,原型为 返回值类型为double,无形参 的函数指针。using func = double;
:定义一种类型func,原型为doubleusing func = double();
定义一种类型func,可以用来声明 某个返回值类型为double,无形参 的函数。using func = double(*)();
定义一种类型func,原型为 返回值类型为double,无形参 的函数指针。
提问:尝试解释以下代码含义:
double*(*func)();
double* *func();
double (func)();
答案:
- 定义一个函数指针func,可以指向一类返回值类型为double*,无形参的函数
- 声明一个返回值double**,无形参的函数func,或许写成
double** func();
会更好看一些 - 同
double func();
当函数指针和数组搭配时,你可能会看到诸如int *(*(*f)[5])();
的代码,为了理解它,你可以阅读 当函数指针与数组相遇。