功能

功能允许结构的代码段的程序来执行各项任务。

在C ++中,一个功能是一组被赋予一个名称,并且可以从节目的某一点调用语句。最常见的语法定义一个函数为: 式中: - 是函数返回值的类型。 - 是由该函数可以被调用的标识符。 - (多达需要):每个参数包含一个类型后跟的标识符,与每个参数从下用逗号分开。每个参数看起来非常像一个普通的变量声明(例如:),并且在功能作为常规变量,它是本地函数中的事实的行为。参数的目的是允许将参数传递给该函数从那里它被从调用的位置。 - 是函数体。它是由大括号{}指定哪些函数实际上确实包围的语句块。 让我们来看一个例子:

type name ( parameter1, parameter2, ...) { statements }


type
name
parameters int x
statements



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// function example
#include <iostream>
using namespace std;

int addition (int a, int b)
{
  int r;
  r=a+b;
  return r;
}

int main ()
{
  int z;
  z = addition (5,3);
  cout << "The result is " << z;
}
结果是8


这个方案是在两个功能分为: additionmain。请记住,无论它们被定义的顺序,一个C ++程序总是通过调用启动 main。实际上, main是自动调用的唯一功能,而如果它的功能是从被称为仅执行在任何其他功能的代码 main(直接或间接)。

在上面的例子中, main通过声明变量开始 z类型 int,经过正确的,执行的第一个函数调用:调用 addition。对函数的调用遵循非常相似,其声明的结构。在上面的例子中,调用 addition可以比它的定义只用几行更早:

 
在函数声明的参数有明确的对应关系,以在函数调用传递的参数。该调用传递两个值, 5并且 3,该功能; 这些对应于参数 ab宣布为功能 addition

在在其功能是从内部被称为主点,控制被传递给函数 addition:在这里,执行 main停止,一旦将只恢复 addition功能结束。在函数调用的时刻,两个参数(的值 53)被复制到局部变量 int aint b函数内。

然后,内 addition,另一本地变量声明( int r),并通过表达式的装置 r=a+b,的结果 a加上 b分配给 r; 其中,对于这种情况,在这里 a是5和 b为3时,意味着8被分配到 r

在函数中的最后陈述:

 
return r;
 


完函数 addition,并返回控制返回到调用函数点; 在这种情况下:起作用 main。在这一刻,节目恢复原道 main在其被通过调用中断的相同点正好返回 addition。但另外,因为 addition具有返回类型,呼叫被评价为具有一个值,并且该值是在截至return语句中指定的值 addition:在此特定情况下,本地变量的值 r,这在的时刻 return语句具有8值

 
。因此,在调用 addition是与由该函数返回的值的表达式,在此情况下,该值,8,被分配到 z。这是因为如果整个函数调用( addition(5,3))被返回的值替换(即8)。

然后主要通过调用打印该值:

 
cout << "The result is " << z;
 


函数实际上可以在程序中调用多次,和它的参数自然也不会仅仅局限于文字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// function example
#include <iostream>
using namespace std;

int subtraction (int a, int b)
{
  int r;
  r=a-b;
  return r;
}

int main ()
{
  int x=5, y=3, z;
  z = subtraction (7,2);
  cout << "The first result is " << z << '\n';
  cout << "The second result is " << subtraction (7,2) << '\n';
  cout << "The third result is " << subtraction (x,y) << '\n';
  z= 4 + subtraction (x,y);
  cout << "The fourth result is " << z << '\n';
}
的第一个结果是5
第二个结果是5
第三个结果是2
第四个结果是6


类似于 addition前面的例子中的功能,本实施例定义了一个 subtract功能,即简单地返回它的两个参数之间的差异。此时, main调用此函数几次,这表明更可能的方式,其中的函数可以被调用。

让我们来看看这些电话,铭记每一个函数调用本身是一个被评估为返回值的表达式。再次,如果函数调用本身的返回值替换你能想到的吧:

1
2
z = subtraction (7,2);
cout << "The first result is " << z;
 


如果我们更换其返回值的函数调用(即5),我们将有:

1
2
z = 5;
cout << "The first result is " << z;
 


用同样的方法,我们可以解释:
 
cout << "The second result is " << subtraction (7,2);
 


如:
 
cout << "The second result is " << 5;
 


因为5返回的值 subtraction (7,2)

如果是:

 
cout << "The third result is " << subtraction (x,y);
 


传递到减法的参数是变量而不是文字。这也是有效的,并且工作正常。该函数调用的价值观 xy分别为5和3,返回2的结果是:必须在呼叫的时刻。

第四个电话是再次类似:

 
z = 4 + subtraction (x,y);
 


唯一的加成是,现在的函数调用也是加法运算的操作数。再次,结果是一样的,如果函数调用由其结果所取代:6。注意,这多亏相加可交换性,上面还可以写为:

 
z = subtraction (x,y) + 4;
 


用完全相同的结果。还需要注意的是分号并不一定是函数调用后去,但是,一如既往,在整个语句的末尾。再次,背后的逻辑可能很容易再看到通过更换其返回值的函数调用:

1
2
z = 4 + 2;    // same as z = 4 + subtraction (x,y);
z = 2 + 4;    // same as z = subtraction (x,y) + 4; 
 


无类型的功能。使用无效的

对于功能上面显示的语法: 要求开始与一个类型的声明。这是由该函数返回值的类型。但是,如果函数不需要什么返回值?在这种情况下,要使用的类型是,这是一种特殊的类型来表示没有的值。例如,简单地打印消息的功能可能不需要返回任何值:

type name ( argument1, argument2 ...) { statements }

void

1
2
3
4
5
6
7
8
9
10
11
12
13
// void function example
#include <iostream>
using namespace std;

void printmessage ()
{
  cout << "I'm a function!";
}

int main ()
{
  printmessage ();
}
我是一个功能!


void也可以在函数的参数列表用于明确指定调用时该函数没有实际参数。例如, printmessage可能已被定义为:

1
2
3
4
void printmessage (void)
{
  cout << "I'm a function!";
}
 


在C ++中,空参数列表可以用来代替 void用同样的意思,但使用的 void参数列表是由C语言编写,在那里,这是一个需要普及。

事情在任何情况下是可选的是后面的函数名,无论是在其声明中也没有调用它时括号。甚至当函数没有参数,至少有一对空括号应始终附加到函数名称。看看 printmessage被称为在前面的例子:

 
printmessage ();
 


括号是从什么其他种类的声明或说明的区分功能。以下就不会调用该函数:

 
printmessage;
 


主要的返回值

您可能已经注意到的返回类型 mainint,但是在这个最例子和前面的章节中实际上并没有返回任何值 main

那么,有一个问题:如果执行 main正常结束时没有遇到一个 return声明中,编译器假定有一个隐含的return语句,函数结束:

 
return 0;
 


请注意,这仅适用于功能 main的历史原因。与返回类型的所有其他职能应适当结束 return,其中包括一个返回值,即使是从未使用过的语句。

main返回零(隐或显式),它是由环境,该计划成功结束解释。其它值可以通过被返回 main,和某些环境给访问该值以某种方式呼叫者,尽管这种行为不是必需的,也没有平台之间一定便携。对于价值 main的保证在所有平台上以同样的方式来解释是:

描述
0该计划是成功的
EXIT_SUCCESS该方案是成功的(同上)。
该值在头文件中定义<cstdlib>
EXIT_FAILURE该计划失败。
该值在头文件中定义<cstdlib>

由于隐含 return 0;的说法 main是一个棘手的例外,一些学者认为这是很好的做法,明确写入了声明。

参数按值和按引用传递

在早期看到的函数,参数一直传递 由值。这意味着,在调用函数时,什么被传递给功能是对呼叫,它被复制到由函数参数表示的变量的时刻,这些参数的值。例如,拿:

1
2
int x=5, y=3, z;
z = addition ( x, y );
 


在这种情况下,功能除了传递5和3,这是值的副本 xy分别。这些值(5和3)用于初始化设置为在函数的定义参数变量,但功能内的这些变量的任何修改对变量x和外面y的值没有影响,因为x和y分别自己不会传递到通话中的功能,但在那一刻,他们的价值的唯一副本。

 
在某些情况下,虽然,它可能是有用的,从一个功能中访问外部变量。要做到这一点,参数可以通过 参照,而不是 按值。例如,该功能 duplicate在这个代码复制的它的三个参数的值,导致使用作为参数的变量实际上是由呼叫进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// passing parameters by reference
#include <iostream>
using namespace std;

void duplicate (int& a, int& b, int& c)
{
  a*=2;
  b*=2;
  c*=2;
}

int main ()
{
  int x=1, y=3, z=7;
  duplicate (x, y, z);
  cout << "x=" << x << ", y=" << y << ", z=" << z;
  return 0;
}
X = 2,Y = 6,Z = 14


要访问它的参数,函数声明其参数 引用。在C ++中,引用被用符号(表示 &以下的参数类型),如在所采取的参数 duplicate在上面的例子。

当一个变量传递 引用,什么传递不再是一个副本,但变量本身,由函数参数标识的变量,变成某种方式传递给函数的参数,并在他们的相应的局部变量的任何修改相关功能反映在作为调用参数传递的变量。

 

其实 abc成为对函数调用传递的参数(别名 xyz),并在任何变化 a中的作用实际上是修改变量 x函数外。上的任何变化 b修改 y的,任何变化 c修改 z。这就是为什么当,在这个例子中,功能 duplicate修改的变量的值 abc,的值 xy以及 z受影响。

如果不是重复定义为:

 
void duplicate (int& a, int& b, int& c) 
 


当时它没有符号迹象来定义:

 
void duplicate (int a, int b, int c)
 


这些变量不会通过 引用,但 按价值,而不是创造它们的值的副本。在这种情况下,程序的输出本来的值 xyz不被修改(即,1,3和7)。

效率的考虑和const引用

调用由值取参数的函数会导致做出的值的副本。这是基本的类型,例如一个相对便宜的操作 int,但是,如果该参数是一个大的化合物的类型,它可能会导致在某些开销。例如,请考虑以下功能:

1
2
3
4
string concatenate (string a, string b)
{
  return a+b;
}
 


该函数有两个字符串作为参数(按价值计算),并返回它们连接起来的结果。通过按值传递的参数,功能势力 ab要传递给函数的参数拷贝,当它被调用。并且,如果这些是长串,这可能意味着拷贝大量的数据只是为函数调用。

但是这个副本可以完全避免,如果这两个参数都做 参考

1
2
3
4
string concatenate (string& a, string& b)
{
  return a+b;
}
 


通过参考参数不需要的拷贝。功能直接操作(的别名)作为参数传递的字符串和,至多,这可能意味着某些指针的传递给函数。在这方面,的版本 concatenate以引用比版本了结值更有效,因为它并不需要复制昂贵到拷贝串。

在另一面,参考参数的函数通常被视为一个修改传递参数的功能,因为这就是为什么引用参数实际上是对。

解决的办法是对功能,以保证它的基准参数都不会通过该功能进行修改。这可以通过有资格的参数作为常数来完成:

1
2
3
4
string concatenate (const string& a, const string& b)
{
  return a+b;
}
 


通过限定它们为 const,所述功能被禁止修改的既不值 a也不 b但实际上可以访问它们的值作为参考(的参数别名),而无需使琴弦实际副本。

因此, const参考文献提供了类似于由值传递参数的功能,但是与大类型的参数增加的效率。这就是为什么他们是在C ++的复合类型的参数非常受欢迎。请注意虽然,对于大多数基本类型,存在效率没有显着的差异,在某些情况下,常数引用甚至可能效率较低!

内联函数

调用函数通常会导致一定的开销(堆叠参数,跳跃,等等),并且因此对于非常短的功能,它可以更有效地简单地插入其中它被称为函数的代码,而不是执行该处理正式调用的函数。

前面的函数声明与 inline说明通知联展开优于通常的函数调用机制特定函数的编译器。这并不在函数的所有行为的改变,而只是用来表明,由函数体生成的代码应在每个点的函数被调用被插入,而不是一个普通的函数调用被调用时,编译器。

例如,连击以上功能,可以在线声明:

1
2
3
4
inline string concatenate (const string& a, const string& b)
{
  return a+b;
}
 


该通知时,编译器 concatenate被调用时,程序更喜欢的功能被内联扩展,而不是进行正常通话。 inline仅在函数声明中指定,而不是当它被调用。

请注意,大多数编译器优化已有的代码来生成内联函数,当他们看到提高效率的机会,即使没有明确标有 inline说明。因此,这说明仅仅表明直列是首选此功能的编译器,虽然编译器就可以不要内联它,否则优化。在C ++中,优化是委托给编译器,它可以自由地产生任何代码,只要所得到的行为是由码指定的一个任务。

在参数的默认值

在C ++中,功能也可以有可选的参数,这是任何参数都需要在该呼叫,在,例如,具有三个参数的函数可以仅具有两个称为这样的方式。为此,该功能应包括其最后一个参数,它被用来由函数时以更少的参数称为默认值。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// default values in functions
#include <iostream>
using namespace std;

int divide (int a, int b=2)
{
  int r;
  r=a/b;
  return (r);
}

int main ()
{
  cout << divide (12) << '\n';
  cout << divide (20,4) << '\n';
  return 0;
}
6
五


在这个例子中,有两个呼叫起作用 divide。在第一种:

 
divide (12)
 


呼叫只传递一个参数的函数,即使函数有两个参数。在这种情况下,函数假定第二个参数为2(注意函数定义,其中宣布其第二个参数为 int b=2)。因此,其结果为6。

在第二个呼叫:

 
divide (20,4)
 


呼叫传递两个函数的自变量。因此,对于缺省值 bint b=2)被忽略,并且 b需要作为参数传递的值,即4,得到5的结果。

声明函数

在C ++中,标识符只能在表达式中使用,一旦他们被宣布。例如,有些变量 x不能用语句,如声明前被使用:

 
int x;
 


这同样适用于函数。在声明之前的函数不能被调用。这就是为什么,在函数的所有前面的例子中,函数总是在之前定义的 main功能,这是从其中其他函数的调用的功能。如果 main在其它的功能才能被定义,这将打破职能应在使用前申报,所以并不会编译规则。

一个函数的原型可在不实际完全定义的功能,只是提供足够的细节,让参与函数调用的类型被称为声明。自然地,该函数应别处所定义,如同在后面的代码。但至少,曾经宣称这个样子,它已经可以被调用。

声明应包括涉及所有类型(返回类型和它的参数的类型),使用相同的语法在函数的定义中使用,但有一个结束分号替换函数体(语句块)。

参数列表并不需要包括参数名称,但只有它们的类型。参数名称仍然可以指定,但它们是可选的,并且不需要一定匹配在函数定义。例如,调用函数 protofunction与两个int参数可与这些语句的声明:

1
2
int protofunction (int first, int second);
int protofunction (int, int);
 


不管怎么说,包括每个参数的名称总是提高了报关的易读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// declaring functions prototypes
#include <iostream>
using namespace std;

void odd (int x);
void even (int x);

int main()
{
  int i;
  do {
    cout << "Please, enter number (0 to exit): ";
    cin >> i;
    odd (i);
  } while (i!=0);
  return 0;
}

void odd (int x)
{
  if ((x%2)!=0) cout << "It is odd.\n";
  else even (x);
}

void even (int x)
{
  if ((x%2)==0) cout << "It is even.\n";
  else odd (x);
}
请输入数字(0至出口):9
这是奇怪的。
请输入数字(0至出口):6
它是偶数。
请输入数字(0至出口)1030
它是偶数。
请输入数字(0至出口):0
它是偶数。


本实施例确实不效率的一个例子。你也许可以自己编写一个版本的程序与代码一半的线路。总之,这个例子说明如何功能可它的定义之前声明:

下面几行:

1
2
void odd (int a);
void even (int a); 
 


声明的函数的原型。他们已经包含了所有什么必要给他们打电话,他们的名字,类型他们的说法,他们的返回类型( void在这种情况下)。有了这些原型声明,它们可被完全定义之前被调用,从而,例如,放置从它们被称作其中(函数 main的这些功能的实际定义之前)。

但被定义之前声明函数不仅是有用的代码中重组功能的顺序。在某些情况下,如在该特定情况下,声明中的至少一个是必需的,因为 oddeven相互调用; 有一个呼叫 evenodd和呼叫 oddeven。的,因此,没有办法来组织代码,以便 odd被前面所定义 even,以及 evenodd

递归

递归是起到必须由他们自己被称为属性。它是为某些任务,如排序的元素,或计算数的阶乘有用。例如,为了获得一个数字(的阶乘 n!)的数学公式将是:

n! = n * (n-1) * (n-2) * (n-3) ... * 1 
更具体地, 5!(5阶乘)将是:

5! = 5 * 4 * 3 * 2 * 1 = 120 
和一个递归函数来在C ++中可能是计算此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// factorial calculator
#include <iostream>
using namespace std;

long factorial (long a)
{
  if (a > 1)
   return (a * factorial (a-1));
  else
   return 1;
}

int main ()
{
  long number = 9;
  cout << number << "! = " << factorial (number);
  return 0;
}
9!= 362880


请注意,在功能因子,我们纳入到自己的呼叫,但前提是传入的参数是大于1的,因为,否则,该函数将执行一个无限递归循环,其中,一旦它到达0,它将继续以所有乘以负数(可能是在挑衅运行期间的一些点的堆栈溢出)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值