函数

  • 函数用于创建C++程序的模块,因此对C++的OOP(面向对象)至关重要
  • C++函数分两种

    • 有返回值
    • 无返回值

有返回值的函数

  • 有返回值的函数将生成一个值,这个值可赋给变量或在其他表达式中使用

例如

标准C/C++库包含一个名为sqrt()的函数,它返回平方根。假设要计算6.25的的平方根并将其值赋给x,则可以使用此语句

x = sqrt(6.25) //返回值(value)2.5并将其值赋给x
  • 表达式sqrt(6.25)将调用sqrt()函数
  • 表达式sqrt(6.25)被称为函数调用

    • 被调用的函数被称为被调用函数(called function)
    • 包含函数调用的函数叫做调用函数(calling function)(参见图2.6 调用函数)
  • 圆括号中的值(6.25)是发送给函数的信息,这被称为传递给函数

    • 以这种方式发送给函数的值叫做参数
    • 函数sqrt()得到的结果为2.5,并将这个值发送给调用函数
    • 发送回去的值叫做函数的返回值(return value)

可以这么认为,函数执行完毕后,语句中的函数调用部分将被替换为返回的值。因此,这个例子将返回值赋给变量x
简而言之,参数是发送给函数的信息,返回值是从函数中回去的值
(图2.7 函数调用的句法)

  • 使用函数之前,C++编译器需要知道函数的参数类型返回值类型
  • 如果缺少这些信息,编译器将不知道如何解释返回值
  • C++提供这中信息的方式是采用函数原型语句

函数原型

  • 指出函数涉及的类型
  • 函数原型之于函数就像变量声明之于变量一指出涉及的类型。

    • 例如,C++库将sqrt0函数定义成将一个可能)带小数部分的数字(如6.25*)作为参数,并返回一个相同类型的数字。有些语言将这种数字为实数,但是C++将这种类型称为doublesqrt()的函数原型像这样:
double x;
x = qrt(6.25)
  • 原型结尾的分号表明它是一条语句,这使得它是一个原型,而不是函数头

    • 如果省略分号,编译器将将其解释为一个函数头
      在程序中使用sqrt()时,也必须提供原型。可以用以下几种方法实现:
  • 在源代码文件中输入函数原型
  • 包含头问题cmath,其中定义了原型。#include <cmath>
函数原型和函数定义
  • 函数原型只描述函数接口

    • 描述的是发送给函数的信息和返回的信息
  • 函数定义中包含了函数的代码
  • 库文件中包含了函数的编译代码,而头文件中则包含了原型

sqrt.cpp


// sqrt.cpp

#include <iostream>
#include <cmath>

int main()
{
    using namespace std;

    double area;
    cout << " enter a area,insquare feet,of you home: ";
    cin >> area;
    double side;
    side = sqrt(area);
    cout << " that's a square " << side
         << " feet to the side. " << endl;
    cout << " how fascinating! " << endl;
    return 0;
}
  • 由于sqrt()使用的是double值,因此将变量声明为这种类型。

    • double类型使得变量areaside能够储存带消暑的值
  • C++允许在程序的任何地方声明新变量,因此sqrt.cpp在要使用side时才声明它
  • C++允许在创建变量时对它进行赋值,因此可以这样做

    • 这个过程叫做初始化(initialization)
double site = sqrt(area)

函数变体

有些函数需要多项信息。这些函数使用多个参数,参数间用逗号分开。例如,数学函数pow0接受两 个参数,返回值为以第一个参数为底,第二个参数为指数的幂。该函数的原型如下:

double pow(double, double);

若要计算5的8次方,可以这样使用该函数

answer = pow(5.0,8.0);

另外有些函数不接受任何参数,例如rand()参数,该函数不接受任何参数,并返回一个随机整数
该函数的原型如下:

int rand(void); //不带参数的函数的原型
  • 关键词void明确指出,该函数不接受任何参数
  • 若过让括号为空,则C++将其解释为不接受任何参数的隐形声明。可以这样使用
my Guess = rand(); //不带参数的函数调用
  • 在C++中,函数调用中必须包括括号,即便没有参数

没返回值的函数

还有一些函数没有返回值。

例如,假设编写了一个函数、它按美元、美分格式显示数字。当向它传递参数23.5时、它将在屏幕上显示$23。50。由于这个函数把值发送给屏幕,而不是调用程序:因此不需要返回值。可以在原型于使用关键字void来指定返回类型、以指出函数没有返回值。

void bucks (double); //原型对于没有返回值的函数
  • 由于它不返回值,因此不能将该函数调用放在赋值语句或其他表达式中。相反,应使用一条纯粹的函数调用语句:
bucks(12345.67)

在有些语言中,有返回值的函数被称为函数( finction ),没有返回值的函数被称为过程( procedure) 或子程序( subroutine)。但C++与C-样,这两种变体都被称为函数。

用户定义的函数

  • 每个C++程序都必须有一个main()程序,用户必须对它进行定义
  • 库函数一样,也可以通过函数名调用用户定义的函数
  • 对于库函数,在使用之前必须提供其原型,通常把原型放到main()定义之前
// ourfunc.cpp //定义自己的函数

#include <iostream>
void simon(int); //simon的函数原型

int main ()
{
    using namespace std;
    simon(3); //调用simon()函数
    cout << " pick an integer: ";
    int count;
    cin >> count;
    simon(count); //call it again
    cout << " done! " << endl;
    return 0;
}
void simon(int n) //定义simon()函数
{
    using namespace std;
    cout << " simon says your toes " << n << "  times. " << endl;

} //void函数下不需要return语句
  • main()函数两次调用simon()函数,一次的参数为3,另一次参数为变量count
  • 在这两次调用之间,用户输入一个整数来设置conut的值
函数格式
  • 在ourfunc.cpp中,simon()main()的定义采用格式相同

    • 首先,有一个函数头
    • 然后是花括号中的函数体
  • 定义simon()的源代码位于main()的后面。和C语言一样。

    • C++不允许将函数定义嵌套在另一个函数定义中
    • 每个函数定义都是独立的,每个函数定义都是平等
函数头

simon()函数的函数头如下

void simon(int n)
  • 开头的void表明simon()没有返回值,因此调用它不会生成可在main()中将其赋给变量的数字
  • 括号中的int n表明,使用simon()时,应提供一个int参数

    • n是一个新的变量,函数调用是传递的值将被赋给它
    • 下面的函数调用将3赋给simon()中定义的变量n
simon(3);
  • 当函数体中的cout语句使用n时,将使用函数调用中传递的值

    • 函数调用simon(count)导致函数显示512,是因为其是赋给count的值
  • 括号的int n表明,使用simon()时,应提供一个int参数
  • n是一个新的变量,函数调用时传递的值将被赋给它
  • 因此下面的函数将3赋给simon()函数头中定义的变量n
simon(3);
  • 当函数体中的cout语句使用n时,将使用函数调用时传递的值
  • 示例运行中,函数调用simon(count)导致函数显示512是因为其是赋给count的值

    • 简单的说,simon()函数头表明该函数接受一个int参数,不返回任何值
  • 由于无返回值,所以不能这样使用它
simple = simon(3); //不允许使用空函数
  • 对于有返回值的的函数,应使用return来提供返回值,并结束函数

这在逻辑上是一致的: main()返回一个int值, 而程序员要求它返回整数0。但可能会产生疑问,将这个值返回到哪里了呢?毕竟,程序中没有哪个地方可以看出对main()的调用

sqpeeze = main();“absent from our programs

答案是,可以将计算机操作系统(如UNIX或Windows)看作调用程序。因此,main()的返回值并不是返回给程序的其他部分,而是返回给操作系统。很多操作系统都可以使用程序的返回值。例如,UNIX外壳脚本和Windows命令行批处理文件都被设计成运行程序,并测这它们的通回值(通信将退出值)通常的约定是,退出值为0则意味着程序运行成功,为非零则意味着存在问题。因此,如果C++程序无法 打开文件,可以将它设计为返目一个字零值。 然后,便可以设计一个外壳脚本或批处理文件来运行该程序,如果该程序发出指示失败的消息,则采取其他措施。

关键字
  • 关键字是C+++专用的,不能用作他用
  • 其他函数名和对象也都不是关键字

用户定义的有返回值的函数

// convert.cpp
#include <iostream>
int stonetolb(int);
int main()
{
    using namespace std;
    int stone;
    cout << " Enter stone: ";
    cin >> stone;
    int pounds = stonetolb(stone);
    cout << stone << " stone = ";
    cout << pounds << " pounds. " << endl;
    return 0;

}
int stonetolb(int sts)
{
    return 14 * sts;
}
  • main()中,程序使用cin来给整型变量stone提供一个值
  • 这个值被作为参数传递给stonetolb()函数

    • 在该函数中,这个值被赋给变量sts
    • 然后,stone()关键词return14*sts返回main(),这表明retunrn后面不一定得跟一个简单的数字
  • 这里使用一个较为复杂的表达式,避免创建了一个新变量

    • 将结果赋给该变量,然后返回
  • 这些例子表明,函数原型描述了函数接口,即函数如何与程序的其他部分交互
  • 函数列表指出了返回值的类型
  • 参数列表指出了何种信息将被传递给函数
  • 函数stonetolb()包含了全部的函数特性

    • 有函数头和函数体
    • 接受一个参数
    • 返回一个值
    • 需要一个原型

在多函数程序中使用using编译指令

ourfunc.cpp中,两个函数中都包含下面一条编译指令

using namespace std;
  • 这是因为每个函数都使用了cout,因此需要能够访问位于名称空间std中的cout定义
  • ourfunc.cpp中,可以将编译指令放在函数的外面,即位于两个函数的前面
# include <iostream>
using namespace std;
  • 能让程序访问名称空间std的方法有多种,以下是其中的4种

    • using namnspace std;放在函数定义之前,让文件中所有的函数都能够使用名称空间std中所有的元素
    • using namespace std;放在特定的函数定义中,让该函数能够使用名称空间std中的所有元素
    • 在特定的函数中使用类似using std::cout;这样的编译指令,而不是using namespace std, 让该函数能够使用指定的元素,如cout
    • 完全不使用编译指令 using,而在需要使用名称空间std中的元素时,使用前缀std::如下所示:
std::cout << "I'm using cout and endl from the std namespace" << std::endl;

总结

  • C++程序由一个或者多个被称为函数模块组成
  • 程序从main()开始执行,因此该函数必不可少
  • 程序由函数头函数体组成

    • 函数头指出函数的返回值(如果有的话)的类型和函数期望通过函数传递给他的信息的类型
    • 函数体由一系列位于花括号{`}中的C++语句`组成
  • 有多种类型的C++语句,包括以下6种

    • 声明语句:定义函数中使用的变量的名称和类型。
    • 赋值语句:使用赋值运算符(=)给变量赋值。
    • 消息语句:将消息发送给对象,激发某种行动。
    • 函数调用:执行函数。被调用的函数执行完毕后,程序返回到函数调用语句后面的语句。
    • 函数原型:声明函数的返回类型、函数接受的参数数量和类型。
    • 返回语句:将一个值从被 调用的函数那里返回到调用函数中。

类是用户定义的数据类型规范,它详细描述了如何表示信息以及可对数据执行的操作。对象是根指类规范创建的实体,就像简单变量是根据数据类型描述创建的实体一样。
C++提供了两个用于处理输入和输出的预定义对象(cin和cout),它们是istreaemostream类的实例,这两个类是在iostream文件中定义的。为ostream类定义的插人运算符(<<)使得将数据插大输出流成为可能:为itrem类定义的抽取运算符(>>)能够从输人流中抽取信息。cin 和cout都是智能对象,能够根据程序上下文自动将信息从一种形式转换为另一 种形式。

  • C+可以使用大量的C库函数。要使用库函数,应当包含提供该函数原型的头文件。
最后修改:2021 年 07 月 11 日 01 : 50 PM
如果你喜欢我的文章,不妨赞赏一下。