zoukankan      html  css  js  c++  java
  • 【c++ primer】第八章 函数探幽

    一,C++内联函数

            定义:  inline double  square (double x){return x*x;}//含有关键字inline的内联函数

            描述:内联函数类似于宏的定义与调用

            使用:调用内联函数时候,不用跳到另一个位置执行代码,而是将调用内联函数代码用相应内联函数替换。

            区别:普通函数调用时候,跳到函数处执行完,返回再执行下一条语句。

                       内联函数调用时候,直接将代码复制过来执行,省去了跳过去然后返回的过程

                        宏:只是简单的形式上的替换

                                例:#define  square(x)  x*x

                                        square(2+3)= 2+3*2+3;

                        内联函数:相当于调用函数代码

                                例:inline  int square(int x){return x*x}

                                         square(2+3)=5*5;

            注意:内联函数不允许递归,内联函数不宜代码过长

    二,引用变量

            定义:引用是已定义的变量的别名,主要用作函数的形参。int   &data代表 data是指向int的引用

            用法:int   a=3;   int  &b=a;   //改变b 的值相当于改变a的值

            注意:必须在声明引用的时候,初始化  int  &a=data;类似于const指针

            例子:       

    #include <iostream>
    using namespace std;
    int main()
    {
        int rats=101;
        int &rodents = rats;
        cout<<"rats="<<rats<<endl;
        cout<<"rodents="<<rodents<<endl;
    
        cout<<"rats address="<<&rats<<endl;
        cout<<"rodents address="<<&rodents<<endl;
        
        int bunnies =50;
     
        rodents=bunnies;
        cout<<"rats="<<rats<<endl;
        cout<<"rodents="<<rodents<<endl;
    
        cout<<"rats address="<<&rats<<endl;
        cout<<"rodents address="<<&rodents<<endl;
        
        return 0;
    }
           输出:
    rats=101
    rodents=101
    rats address=0xbf89c2c4
    rodents address=0xbf89c2c4
    rats=50
    rodents=50
    rats address=0xbf89c2c4
    rodents address=0xbf89c2c4
    

    解释:rodents 是 rats的 引用,就是同名变量,存储在同一块地址。更改一个的值,同时更改两个变量。

    三,引用用作函数参数

           意义:使得函数中的变量名成为调用程序中的变量的别名(类似全局变量)

           区别:c语言只能按值传递(使用调用程序中值的拷贝),也可以采用按指针传递

           例子:             

    #include <iostream>
    using namespace std;
    
    void swaptr(int &a,int &b)//quote
    {
        int temp;
        temp=a;
        a=b;
        b=temp;
       
    }
    void swaptp(int *a,int *b)//point
    {
        int temp;
        temp=*a;
        *a=*b;
        *b=temp;
       
    }
    int main()
    {
        int i=1,j=2;
        cout<<"i="<<i<<" ;j="<<j<<endl;
        swaptr(i,j);
        cout<<"i="<<i<<" ;j="<<j<<endl;
        swaptp(&i,&j);//not quote is address symbol 
        cout<<"i="<<i<<" ;j="<<j<<endl;
        return 0;
    }
           解释:void swaptp(int * a,int *  b) //其实是将地址传递给函数,可以采用  int * p1,*p2;swaptp(p1,p2)或者int i,j;  swaptp(&i,&j);

                      p1跟&i都代表地址,而 a也代表地址。所以应该传递进来地址。

                      相当于直接使用原地址操作,原来的数值

    四,引用的属性和特别之处

           引例:double  refcube(double &ra){ra*=ra*ra;   return ra; }//修改ra相当于修改 传递进来的值

           常量引用:如果1,想让函数使用传递给他的信息。2,不对这些信息进行修改。3,想使用引用 使用常量引用(const double &ra)

           注意:当数据比较大(结构,类)引用参数将很有用,避免复制占用的各种资源

           临时变量产生的情况:1,实参类型正确但不是左值(可被引用的数据对象:变量,数组元素,结构成员,引用)

                                               2,参数的类型不正确,但可以转换为正确类型

           临时变量生存过程:只在函数调用期间存在,此后编译器将可以随便将其删除。

                                            double side =3.0;

                                            long edge=5L;

                                            refcube(7.0);//类型正确,没有名称,生成临时变量

                                            refcube(side+10.0);// 类型正确,没有名称,生成临时变量         

                                            refcube(edge);// 参数类型不正确     

    五,将引用用于结构

            引例:      

    #include <iostream>
    using namespace std;
    
    struct sysop
    {
       char name[26];
       char quote[64];
       int  used;
       
    };
    
    
    const sysop &use(sysop &sysopref)//返回类型为 引用 ,参数类型为结构的引用
    {
      cout<<sysopref.name<<endl;
      cout<<sysopref.quote<<endl;
      sysopref.used++;
    
      return  sysopref;
    }
    
    int main()
    {
    
       sysop  looper={    //初始化结构
        "tianshuai",
        "I am a boy",
        1
         };
       
       use(looper);调用函数
       cout<<"Looper:"<<looper.used<<endl;
     
       sysop   copycat=use(looper);
       
       cout<<"Looper:"<<looper.used<<endl;
       cout<<"copycat:"<<copycat.used<<endl;
       
       cout<<"use(looper):"<<use(looper).used<<endl;
      
       
       return 0;
    }
         说明:返回值       是将返回的值复制到临时存储区域,随后调用程序访问该区域

                    返回引用   是调用程序直接访问返回值。跨过临时存储区域

         注意:避免返回 当函数终止时不再存在得内存单元引用

                    应该避免示例:

                                  const  sysop & clone(sysop &sysopref)

                                  {

                                             sysop   newquy;

                                             newquy=sysopref;

                                             return   newquy;

                                   }//函数结束时候 newquy 将被释放掉

        

        如果想使用局部变量得引用,使用new分配新的内存区域:sysop  newquy=new sysop;

    六,将引用用于类对象

            在C++中  "***"为const char * 类型,而string类定义了一种 char * 到string 的转换功能

    七,何时使用引用参数

            原因:1)程序员修改调用函数中的数据对象

                       2)传递引用,可以提高程序运行效率

    八,默认参数

           从右向左指定默认值    char * left(const char * str, int n=9)

           调用时候 left("addf")

                          left("asdf",5) 都是合法调用

    九,函数重载

           可以使用相同函数名,不同的参数列表。参数列表是函数重载的关键

           误区:1)引用跟变量 不算不同参数列表

                            print(char a)

                            print(char &a)  //这两个不能共存

                     2)不同返回类型,相同参数列表不算重载

      十,函数模板

             定义:通用的函数描述

                        template  <class Any>            //定义模板类型

                       // template  <template Any>    //template 在新的编译器里面可以替换class

                        void    swap(Any &a,Any &b)

                        {

                            Any  temp;

                            temp=a;

                            a=b;

                            b=temp;

                        } 

             应用:如果将同一种算法,用于不同类型参数。使用模板

             注意:函数模板不能缩短可执行程序,最终各个程序都会定义成各自独立的函数。而最终的源码不包含任何模板。

             源码:

    #include <iostream>
    using namespace std;
    
    //template <class Any>
    //void  Swap(Any &a,Any &b);
    
    
    template <class Any>
    void  Swap(Any &a,Any &b)
    {
       Any temp;
       temp =a;
       a=b;
       b=temp;sd
    }
    
    
    int main()
    {
      int i=1,j=2;
      cout<<"i="<<i<<endl;
      cout<<"j="<<j<<endl;
      swap(i,j);
      cout<<"i="<<i<<endl;
      cout<<"j="<<j<<endl;
      
      return 0;
    }
    传递什么参数,Any 变成什么类型

    十一,实例化和具体化

             1)隐式实例化:函数模板并非函数定义,但使用int的模板实例是函数定义,是由于使用Swap()函数时提供了int 参数

             2)显式实例化的格式:template 返回值类型 函数名<数据类型>(具体函数类型 形参);

                          例如:template void func<double>(double const&);

                   已经实例化的函数不能再次实例化

            3)显式具体化:

                   假设定义了如下结构:
                   strut job
                   {
                         char name[40];
                         double salary;
                         int floor;
                  }
                 可以使用上面定义的模板函数进行两个job实例的交换功能,但是如果只想对结构中的部分成员进行交换(如salary和floor),则可以使用显式具体化。如下:
                 template <> void Swap<job> (job & , job &);     //显式具体化函数定义

    十二,编辑器如何选择函数版本

             1)完全匹配,但常规函数由于模板函数

             2)提升转换,参数列表char和short自动转换为int ,float转换为double

             3)  标准转换,int转换为char  long转换为double

             4)用户定义的转换,类生命中定义的转换


                     

           


                  



           

            


  • 相关阅读:
    HDFS、YARN、Mapreduce简介
    List<object> 转 List<T>
    CTR+A组合键 以及终止按键事件传递
    BackgroundWorker 的输入、输出参数、进度条与文字刷新、取消机制、返回事件
    读取Excel文件的两种方法比较 以及用NPOI写入Excel
    浅复制不能传递,重新赋值就重新浅复制
    gridControl添加右键菜单
    C#设置Excel行高、列宽
    任意字符串(包括空串)都包含空白字符串
    JAVA 在程序中存储和修改信息
  • 原文地址:https://www.cnblogs.com/secbook/p/2655038.html
Copyright © 2011-2022 走看看