首页 >后端开发 >C#.Net教程 >第六章C++:函数基础与应用

第六章C++:函数基础与应用

php是最好的语言
php是最好的语言原创
2018-08-06 10:47:131514浏览

第六章 函数

函数是一个命名了的代码块,通过调用函数执行相应的代码。

函数基础

  • 通过调用运算符(call operator)来执行函数。其形式是一对圆括号。

  • 函数的调用完成两项工作(如下),此时主调函数(calling function)的执行被暂时中断,被调函数(called function)开始执行。

    • 用实参初始化函数对应的形参。

    • 将控制权转移给被调函数。

  • return语句:

    • 返回return语句中的值

    • 将控制权从被调函数移回主调函数

局部对象

  • 名字有作用域,对象有生命周期(lifetime)

  • 自动对象(automatic object):当函数的控制路径经过变量定义语句时创建该对象,当达到定义所在的块末尾时销毁它。

  • 局部静态对象:程序执行路径第一次经过对象定义语句时初始化,知道程序终止才被销毁。

    • 将局部变量定义为static获得,例如:
      <br>//统计函数count_calls ()被调用了多少次 <br>size_t count_calls () <br>{ <br>static size_t ctr = 0;  //调用结束后,这个值仍然有效 <br>return ++ctr; <br>} <br>int main() <br>{ <br>for (size_t i = 0; i != 10; ++i) <br>cout 9cead6dff3b3c0b9daf1c442322e3446 lst;    //默认初始化,T类型元素的空列表 <br>initializer_list8742468051c85b06f0a0af9e3e506b5c lst{a,b,c...}; <br>//lst的元素数量和初始值一样多;lst的元素是对应初始值的副本;列表中的元素是const <br>lst2(lst) <br>lst2 = lst  //拷贝或复制一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本元素共享 <br>lst.size()  //列表中元素的数量 <br>lst.begin() //返回指向lst中首元素的指针 <br>lst.end()   //返回指向lst中尾元素下一位置的指针 <br>

返回类型和return语句

  • 引用返回左值,其他返回类型得到右值。

  • 列表初始化返回值:C++11新标准规定,函数可以返回花括号包围的值的列表。

主函数main的返回值

  • 允许main函数没有返回值(若没有,编译器隐式地插入return 0)

  • 返回0表示执行成功,其他值依机器而定。

  • 为了使返回值与机器无关,cstdlib头文件定义了两个预处理变量,分别表示成功和失败:
    <br>return EXIT_FAILURE; <br>return EXIT_SUCCESS; <br>//因为它们是预处理变量,所以既不能在前面加上std::,也不能在using声明里出现。 <br>

返回数组指针

  1. 使用类型别名
    <br>typedef int arrT[10];   //arrT是一个类型别名,它表示的类型是含有10个整数的数组 <br>using arrT = int[10];   //与上一句等价 <br>arrT* func(int i);      //func返回一个指向含有10个整数的数组的指针 <br>

  2. 声明一个返回数组指针的函数,形式如下
    <br>Type (*function(parameter_list)) [dimension] <br>//Type表示返回的数组指针指向的数组元素类型 <br>//dimension表示数组的大小 <br>//例如: <br>int (*func(int i)) [10]; <br>

  3. 使用尾置返回类型(C++11)
    <br>auto func(int i) -> int(*)[10]; <br>

  4. 使用decltype
    <br>int odd[] = {1,3,5,7,9}; <br>int even[] = {0,2,4,6,8}; <br>decltype(odd) *arrPtr(int i) <br>{ <br>    return (i % 2) ? &odd : &even;  //返回一个指向数组的指针 <br>} <br>

函数重载

如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载(overloaded)函数

  • 不允许两个函数除了返回类型外其他所有要素都相同。

  • 重载与作用域:一旦在当前作用域中找到了所需的名字,编译器就会忽略掉外层作用域中的同名实体。

特殊用途语言特性

介绍三种函数相关的语言特性:默认实参、内联函数、constexpr函数。

默认实参

  • 调用包含默认实参的函数时,可以包含该实参,也可以省略该实参。

  • 一旦某个形参被赋予了默认值,它后面所有的形参都必须有默认值。

内联函数(inline)

调用函数一般比求等价表达式的值要慢,内联函数可避免函数调用的开销。
- 将函数指定为内联函数,通常就是将它在每个调用点上“内联地”展开。

constexpr函数

  • 函数的返回类型和所有的形参类型都得是字面值类型。

  • 函数中必须有且只有一条return语句。

  • constexpr函数被隐式地指定为内联函数。

内联函数和constexpr函数通常定义在头文件中

调试帮助

程序可以包含一些用于调试的代码,但这些代码只在开发程序时使用。当应用程序编写完成准备发布时,要先屏蔽掉调试代码。这种方法用到两项预处理功能:assert和NDEBUG。

assert预处理宏

#include <cassert>assert(expr);//首先对expr求值,//如果表达式为假(即0),assert输出信息并终止程序的执行。//如果表达式为真(即非0),assert什么也不做。//例如:对一个文本进行操作的程序可能要求所给定单词的长度都大于某个阈值。assert(word.size() > threshold;

NDEBUG预处理变量

  • assert的行为依赖于一个名为NDEBUG的预处理变量的状态。如果定义了NDEBUG,则assert什么也不做。默认状态下没有定义NDEBUG,此时assert将运行执行时检查。

    • 使用#define语句定义NDEBUG,从而关闭调试状态。

    • 很多编译器都提供了命令行选项使我们可以定义预处理变量。
      <br>$ CC -D NDEBUG main.C   #微软编译器中用 /D <br>

  • 这只是调试程序的辅助手段,不能代替真正的逻辑检查,也不能代替程序本应该包含的错误检查。

  • 除了assert以外,也能使用NDEBUG编写自己的条件调试代码:

//如果定义了NDEBUG,#ifndef和#endif之间的代码将被忽略void print(const int ia[], aize_t size)
{    #ifndef NDEBUG
        //_ _func_ _是编译器定义的一个局部静态变量,用于存放函数的名字,它是const char的一个静态数组。
        cerr << _ _func_ _ << "array size is " << size << endl;    #endif}

除了_ _ func _ _之外,还有其它四个名字:

_ _FILE_ _ 存放文件名的字符串字面值
_ _LINE_ _ 存放当前行号的整型字面值
_ _TIME_ _ 存放文件编译时间的字符串字面值
_ _DATA_ _ 存放文件编译日期的字符串字面值

函数指针

bool lengthCompare(const string &, const string &);//pf指向一个函数,该函数的参数是两个const string的引用,返回值是bool类型。注意圆括号必不可少bool (*pf) (const string &, const string &);    //未初始化

当我们把函数名作为值使用时,该函数自动地转换成指针

pf = lengthCompare;     //pf指向名为lengthCompare的函数pf = &lengthCompare;    //等价赋值语句,&是可选的

调用该函数:

//此三个调用等价bool b1 = pf("hello", "goodbye");bool b2 = (*pf)("hello", "goodbye");bool b3 = lengthCompare("hello", "goodbye");

参考:C++Primer第五版

相关文章:

第四章C++:表达式概念-运算符的应用

第五章C++:语句的相关介绍

以上是第六章C++:函数基础与应用的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn