第六章 函数

本文详细介绍了C++中的函数参数传递,包括引用形参的优势、数组形参的管理技术以及可变形参的使用。此外,还讨论了函数的特殊用途特性,如默认实参、内联函数、constexpr函数和调试工具assert的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、参数传递

        1、在C++中建议使用引用类型的形参替代指针类型的形参。使用引用同时也能避免参数传递时的拷贝,可以提高效率。如果某些类型不支持拷贝操作(如IO类型),函数只能通过引用形参访问该类型对象。如果函数无须改变引用形参的值,最好将其使命为常量引用

    // 比较两个string对象的长度
    bool isShorter(const string &s1, const string &s2)
    {
        return s1.size() < s2.size();
    }

        2、指针或引用形参与const:形参的初始化方式和变量的初始化方式是一样的。

        3、数组形参:

    char str[] = "Fuck you!";
    // 以下三个函数形式都可以用str数组传参,在函数中都可以使用形参对str数组进行访问
    print(const char str[])
    print(const char str[10])
    print(const char *str)

        以上函数在使用形参的时候并不知道实参数组的大小,所以可能引发数组越界。所以产生了以下三种管理指针形参的技术

  • 使用标记指定数组长度
    void print(const char *str)
    {
        if(str)
    	while(*str)	// 只要指针所指的字符不是空字符标记
    	    cout << *str++;
        cout << endl;
    }
    // 以上对于像int类型的数组就不太适用了
  • 使用标准库规范:传递数组首元素和尾后元素的指针
    int ia[] = {1,2,3,4,5,6};
    void print(const int *beg, const int *end)
    {
        while(beg != end)
            cout << *beg++;
        cout << endl;
    }
    // 使用C++ 11标准提供的begin()和end()函数获取数组的首元素指针和尾后指针并作为实参调用函数
    print(begin(ia), end(ia));
  • 显式传递一个表示数组大小的形参
    // const int ia[] 等价于 const int *ia
    void print(const int ia[], size_t size)
    {
        for(size_t i = 0; i != size; ++i)
        {
    	cout << ia[i];
        }
        cout << endl;
    }
    // 调用print
    print(ia, end(ia) - begin(ia));

        函数参数允许定义为数组的引用:

    void print(int (&ia)[10]);	// 定义时的小括号比不可少,纬度是类型的一部分
    int i = 0, j[2] = {0,1}, k[10] = {0,1,2,3,4,5,6,7,8,9};
    print(&i);	// 错误:数组长度不是10
    print(j);	// 错误:数组长度不是10
    print(k);	// 正确

        4、传递多维数组参数

    // 由于多维数组就是数组的数组,在传递多维数组时应该用以下的方式定义
    void print(int (*matrix)[10], int rowSize);	// 传递的数组是由10个整数构成的数组
    voed print(int matrix[][10], int rowSize);	// 与上是等价定义

        5、含有可变形参的函数

  • 实参类型相同:传递initializer_list的标准库类型(头文件<initializer_list>),提供以下操作:
    initializer_list<T> list;                    // 默认初始化
    initializer_list<T> list{a,b,c,d};       // list的元素是对应初始值的副本;列表中的元素是const类型的
    list2(list);
    list2 = list;
    list.size();                                      // 列表中元素的数量
    list.begin();                                    // 返回list中首元素的指针
    list.end();                                       // 返回指向list中尾元素下一位置的指针
  • 省略符形参
  • 可变参数模版

 

二、因为数组不能拷贝赋值,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。定义一个返回数组的指针或引用的函数的方法如下:

    typedef int iarrT[10];		// 含有10个整数的数组类型
    using iarrT = int[10];		// 与上等价定义

    iarrT* function(int i);		// 使用类型别名定义
    int (*function(int i))[10];		// 这种原始定义太繁琐
    auto function(int i) -> int(*)[10];	// C++11中的尾置返回类型
    decltype(iarrT) *function(int i);	// 使用C++11中的decltype类型推断定义

 

三、特殊用途语言特性

        1、默认实参:一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。
        2、内联函数:内联函数可以避免函数调用的开销。一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。很多编译器都不支持内联递归函数,而且一个几十行上百行的代码也不大可能在调用点内联的展开。

              constexpr函数:是指能用于常量表达式的函数。约定:函数的参数和返回值都得是字面值类型,而且函数中必须有且只有一条return语句,函数内可以有其他语句,只要这些语句在运行时不执行任何操作就行。constexpr函数返回的不一定是常量表达式。

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

        3、assert(expr)。assert宏在头文件cassert中定义。
             NDEBUG预处理变量。#define NDEBUG 后,不在运行assert语句。除了用assert以外,还可以结合使用#ifndef NDEBUG、#endif编写自己的条件调试代码。
             预处理器定义了另外4个对调试程序很有用的名字:__FILE__、__LINE__、__TIME__、__DATE__。

 

四、函数指针

    bool lengthCompare(const string &str1, const string &str2);
    bool (*pf)(const string &, const string &);	// *pf两端的括号必不可少
    pf = lengthCompare; 
    pf = &lengthCompare;			// 取地址符是可选的
    bool b1 = pf("hello", "goodbye");
    bool b2 = (*pf)("hello", "goodbye");
    bool b3 = lengthCompare("hello", "goodbye");


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值