美文网首页程序员C++
1. partone---第六章 函数

1. partone---第六章 函数

作者: 守住这块热土 | 来源:发表于2017-10-25 22:57 被阅读0次
    fig1.jpg

    函数是一个命名了的代码块,可有0个或多个参数。


    6.1 函数基础

    局部对象

    • 自动对象: 存在于块执行期间,当块执行完毕时,则内存消失。例如函数的形参。
    • 局部静态对象: 生命周期为第一次定义到程序结束才终止。

    函数声明

    函数声明应该放到头文件中。 这样做的好处在于:同一函数的所有声明一致;想改变函数的接口,只需要改变函数的声明的即可。


    6.2 参数传递

    引用传递: 形参的类型决定了形参和实参的交互方式。 当形参是引用类型时,如其他引用一样,引用形参是对应实参的别名。
    值传递: 将实参的值拷贝给形参,此时形参和实参是两个相互独立的对象。对形参的改变,不会影响到实参的值。

    6.2.1 值传递

    *指针形参

    void reset(int *ip)
    {
      *ip=0;
      ip=0;
    }
    int i=42;
    reset(&i)
    

    此时形参和实参是两个相互独立的对象。
    实现两个数交换的两种方法(C++中,建议使用引用类型代替指针形参)

     void swap1(int *a,int * b)//指针 参数是两个指针变量
    {
       int tmp;
       tmp=*a; //把a指向的值赋给tmp
       *a=*b;   //把b指向的值赋给a指向的值
       *b=tmp;   //把tmp的值赋给b指向的值
       //这样就达到了变换a,b指向的值的目的
     }
    void swap2(int &a,int &b)//引用 参数是两个整型变量的引用
    {
    //引用就是他本身的值,所以直接交换两个的值就行了。
           int tmp;
           tmp=a;
           a=b;
           b=tmp;
    }
    

    6.2.2 引用传递

    使用引用避免拷贝

    当拷贝大的类类型对象或容器对象时,比较低效。

    使引用可返回额外信息

    一个return只能返回一个参数,通过引用带出多个参数。

    6.2.3 const形参和实参

    void fcn(const int i){};
    void fcn(int i){};
    

    上面这两个函数是一样的,不能重载。因为当形参有顶层const时,传给它的是const或非const均可以
    顶层const:指针本身是一个常亮;
    底层const:指针所指的对象是一个常量。

    const  int ci=42;   //顶层const
    

    指针或引用形参与const

    非常量可以初始化一个底层const对象,反之则不行
    同时,一个普通类型的引用,只能用同类型的对象初始化。

    尽量使用常量引用

    顶层const作为形参时,实参传递是const或非const均可;

    例如:
    bool  is_empty(string &s)
    {
      return s.empty();
    }
    
    这种情况下,限制了该函数所能接受的实参类型,无法把const、对
    象、字面值常量或者需要类型转换的对象传递给普通的引用形参。
    另一方面,也可能带来误导,可修改字符串s。
    应该把形参改为 const string &s
    

    6.2.4 数组形参

    数组的两个特性:不允许拷贝数组、数组名转换为指针

    6.2.5 main:处理命令行选项

    int main(int argc, char *argv[])
    {
        //其中argc是argv[][]的行数
    }
    

    6.2.6 含有可变形参的函数---initializer_lsit

    initializer_lsit是一种标准库类型。适用于函数的实参未知,但类型都相同的情况下。

    int icount(initializer_lsit<int> il)
    {
      int count =0;
      for(auto val :il)
      {
          count += val;
      }
      return count;
    }
    icount({1,2,3,4,5});
    

    6.3 返回类型和return语句

    6.3.1 无返回值函数

    函数的返回类型是void时,如果函数末尾没有return时,也可以。因为在函数的最后一句会隐式的调用return

    6.3.2 有返回值函数

    return exp;

    不要返回局部对象的引用或指针

    函数终止后,局部变量的引用将不再指向有效的内存区域。

    引用返回左值
    char &get_val(string &str, int index)
    {
        return str[index];
    }
    
    void main
    {
      string s("a value");
      get_val(s,0) = 'A';  //改为 A value
    }
    

    6.3.3 返回数组的指针

    int (*func(int i))[10];


    6.4 函数重载

    重载函数:名字相同,但是函数参数列表不同。
    注:返回类型不算。

    重载和const形参

    顶层const
    (因为当形参有顶层const时,传给它的是const或非const均可以)。

    (因为当形参有顶层const时,传给它的是const或非const均可以),所以下面两组函数是重复声明。
    Record lookup(phone);
    Record lookup(const phone);
    
    Record lookup(phone*);
    Record lookup(phone* const );
    

    形参是指针或者引用。将是底层const,可通过指向的对象时常量对象还是非常量对象实现重载。
    一方面,const不能转换为其他类型,只能将const转换为const;另一方面,相反的,非const可以转换为const,但是当同时存在非常量和const两个版本的形参时,编译器会优先选择非常量版本的函数,

    Record lookup(Account &);
    Record lookup(const Account &);
    
    Record lookup(phone*);
    Record lookup(phone* const );
    

    6.5 特殊用途语言特性

    6.5.1 默认实参

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

    6.5.2 内联函数和constexpr函数

    将函数指定为内联函数,通常就是在每个调用点进行展开。
    constexpr函数---暂时用不到。

    6.5.3 调试帮助

    assert预处理

    如:assert(expr),如果表达式为真,什么都不做;如果表达式为假,则输出信息并终止程序。

    DEBUG 预处理命令

    如果你把代码夹在#ifdef DEBUG 和对应的 #endif 中间,那么这段代码只有在调试(DEBUG)下才会被编译。也就是说,如果你在RELEASE模式下,这些代码根本就不会存在于你的最终代码里头。

     #include <iostream>
     using namespace std; 
     #ifdef DEBUG
     inline void msg()
    { 
     cout<<"I'm testing"; 
    } 
     #else 
    inline void msg() {} 
     #endif 
    int main()
     {
       msg();
       return 0;
     }
    

    6.6 函数匹配

    背景:有几个重载函数,当一个调用函数调用重载函数时,可能会发生二义性。
    解决办法:寻求最佳匹配。


    6.7 函数指针

    bool lengthCompare(const string &,const string &);

    1. 该函数的函数类型为bool lengthCompare(const string &,const string &)。 函数类型,是由形参列表和返回值决定,函数名称只是函数的别名而已。
    2. 声明一个函数指针,只需要使用指针代替函数即可(因为函数名称仅仅是一个别名)
      bool (*pf) (const string &,const string &)
    3. 如何使用函数指针
      当把函数名作为一个值使用时,该函数会自动的转换为指针。
      指向不同的函数指针之间,是不能转换的,因为代表的函数返回值。
    pf = lengthCompare;   // 指向名为lengthCompare的函数
    pf = &lengthCompare; //等价,取址操作符是可选的。
    
    //直接使用
    bool b1 = pf("hello", "world");
    bool b2 = (*pf) ("hello", "world"); //等价调用
    
    1. 函数指针形参
    //第三个形参是函数类型,自动转换为指向函数的指针
    void useBigger(const string &, const string &, bool  pf (const string &,const string &));
    |
    void useBigger(const string &, const string &, bool  (*pf) (const string &,const string &)); //自动转换为函数指针
    

    如上面,这样显得函数冗长。
    通常:
    typedef bool Func(const string &, const string &) ;
    void useBigger(const string &, const string &, Func));

    相关文章

      网友评论

        本文标题:1. partone---第六章 函数

        本文链接:https://www.haomeiwen.com/subject/whpyyxtx.html