你真的会声明C++的函数吗?

2,393次阅读
没有评论

看到这个标题你可能会觉得很奇怪,函数声明谁不会啊?划走吧。

且慢,看了这篇文章,你也许会怀疑学了假的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类型的变量func
  • double func();:声明一个返回值类型为double,无形参的函数func
  • double *func();:声明一个返回值类型为double*,无形参的函数func
  • double (*func)();:定义一个函数指针func,可以指向一类返回值类型为double,无形参的函数
  • typedef double func;:定义一种类型func,原型为double。
  • typedef double func();:定义一种类型func,可以用来声明 某个返回值类型为double,无形参 的函数。
  • typedef double (*func)();:定义一种类型func,原型为 返回值类型为double,无形参 的函数指针。
  • using func = double;:定义一种类型func,原型为double
  • using func = double();定义一种类型func,可以用来声明 某个返回值类型为double,无形参 的函数。
  • using func = double(*)();定义一种类型func,原型为 返回值类型为double,无形参 的函数指针。

提问:尝试解释以下代码含义:

  1. double*(*func)();
  2. double* *func();
  3. double (func)();

答案:

  1. 定义一个函数指针func,可以指向一类返回值类型为double*,无形参的函数
  2. 声明一个返回值double**,无形参的函数func,或许写成double** func();会更好看一些
  3. double func();

当函数指针和数组搭配时,你可能会看到诸如int *(*(*f)[5])();的代码,为了理解它,你可以阅读 当函数指针与数组相遇

Lyzen
版权声明:本站原创文章,由 Lyzen 2022-08-18发表,共计1620字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码