10. 函数3

内联函数

  1. 在编译代码的时候,与其他程序代码联起来,编译器使用相应的函数代码来替换函数调用

  2. 内联函数运行速度比常规函数稍快,但是需要更多的内存

  3. 如果要使用内联函数,需要采取的措施是:在函数声明前加上inline关键字,或在函数定义前加上inline关键字

  4. 通常可以省略原型,将整个函数的定义放在写原型的地方

  5. 注意:内联函数不能递归

  6. 例子

    #include <iostream>
    // 定义内联函数
    inline double square(double x){
     return x*x;
    } 
    
    int main(){
     using namespace std;
     double a,b;
     double c = 2.0;
     a = square(5.0);
     b = square(4.3+5.7);
     cout << "a的值是:" << a<< endl;
     cout << "b的值是:" << b<< endl;
     cout << "c平方之后的值是:" << square(c)<< endl;
    }
    

引用变量

  1. 引用变量是指给已经定义的变量设置一个别名,比如将abc作为变量a的引用,那么可以交替使用a和abc

  2. 创建引用变量

    1. 在cpp中,使用&符号来指示变量地址,这个符号也可以用来声明引用

    2. 例子

      int cat;
      int &mao = cat; // 将mao设置为cat的别名
      
      • 在这里,&不再是地址运算符,而是类型标识符的一部分
    3. 例子:交替使用引用名和变量名

      /*
       * firstref.cpp
       *
       *  Created on: 2022年3月28日
       *      Author: mayuj
       */
      
      #include <iostream>
      int main()
      {
        using namespace std;
        int cat;
        cat = 101;
        int &mao = cat;
      
        cout << "cat等于:" << cat << endl;
        cout << "mao等于:" << mao << endl;
      
        mao++;
        cout << "cat等于:" << cat << endl;
        cout << "mao等于:" << mao << endl;
      
        cout << "cat内存地址:"<<  &cat << endl;
        cout << "mao内存地址:"<<  &mao << endl;
      
        return 0;
      }
      
      • 可以看出mao和cat值是一样的,地址也是一样的
  3. 将引用作为函数参数

    1. 按引用传递允许被调用的函数能够访问调用函数中的变量

    2. 例子:交换两个值的函数

      #include <iostream>
      void swap_alias(int &a,int &b);  // a和b是int的别名
      void swap_address(int *p,int *q);  // p和q是int的地址
      void swap_variable(int a,int b); // a和b是单纯的变量
      
      int  main()
      {
        using namespace std;
        
        int alias1 = 300;
        int alias2 = 355;
        cout << "原始alias1的值是:" << alias1 << endl;
        cout << "原始alias2的值是:" << alias2 << endl;
        
        cout << "使用传递别名的函数交换alias1和alias2"<< endl; 
        swap_alias(alias1,alias2);
        
        cout << "别名交换之后,alias1的值是" << alias1 << endl;
        cout << "别名交换之后,alias2的值是" << alias2 << endl;
        cout << endl;
        
        int address1 = 100;
        int address2 = 200;
        
        cout << "原始address1的值是:" << address1 << endl;
        cout << "原始address2的值是:" << address2 << endl;
        
        cout << "使用传递地址的函数交换address1和address2"<< endl; 
        swap_address(&address1,&address2);
        
        cout << "别名交换之后,address1的值是" << address1 << endl;
        cout << "别名交换之后,address2的值是" << address2 << endl;
        cout << endl;
        
        int v1 = 150;
        int v2 = 333;
        
        cout << "原始v1的值是:" << v1 << endl;
        cout << "原始v2的值是:" << v2 << endl;
        
        cout << "使用传递变量的函数交换v1和v2"<< endl; 
        swap_variable(v1,v2);
        
        cout << "变量交换之后,v1的值是" << v1 << endl;
        cout << "变量交换之后,v2的值是" << v2 << endl;
        
        return 0;
       } 
       
      
      void swap_alias(int &a,int &b){  // a和b是alias1和alias2的别名,交换a和b就相当于交换了alias1和alias2的值
        int temp;
        temp = a;
        a = b;
        b = temp;
      }
      
      
      void swap_address(int *p,int *q){  // 此处的p是一个int指针,所以p对应的参数是地址
        int temp;
        temp = *p;
        *p = *q;
        *q = temp;
      }
      
      
      void swap_variable(int a,int b){  // 在这里,a和b是复制了v1和v2的值的新变量,所以它们交换之后不会影响原来的值
        int temp;
        temp = a;
        a = b;
        b = temp;
      }
      
      • 可以看到,按值传递的方法没有交换两个变量的值

默认参数

  1. 函数调用中省略实参时自动使用的一个值

  2. 必须通过函数原型来设置默认值,因为编译器通过查看原型来了解函数所使用的参数数量

    char *left(const char *str,int n = 1);
    
  3. 必须从右向左添加默认值,有默认值的参数放到最右边

  4. 例子

    #include <iostream>
    const int SIZE = 80;
    char *left(const char *str,int n = 1);
    
    
    int main()
    {
     using namespace std;
     char sample[SIZE];
     cout << "输入一个字符串:";
     cin.get(sample,SIZE);
     char *ps = left(sample,4);
     cout << "ps的值是:" <<ps << endl;
     delete [] ps;
     
     ps = left(sample);
     cout << "新ps的值是" << ps << endl;
     delete [] ps;
     return 0;
    }
    
    char *left(const char *str,int n){  // 在定义函数的时候不写默认值 
     // 这个函数返回一个指向新字符串的指针
     if (n <0){
         n = 0;
     } 
     char *p = new char[n+1];
     int i;
     for(i =0;i<n&&str[i];i++){
         p[i] = str[i];
     }
     while (i<=n){
         p[i++] = '\0';
     }
     return p;
    }
    

函数重载

  1. 可以有多个同名的函数,但是参数列表不同

  2. cpp使用上下文来确定要使用的重载函数版本

  3. 函数重载的关键就是函数的参数列表,如果两个函数的参数数量和类型相同,参数的排列顺序也相同,那么就称为函数特征标(function signature)相同

  4. 例子

    #include <iostream>
    unsigned long left(unsigned long num,unsigned ct);
    char *left(const char *str,int n =1); 
    
    int main()
    {
     using namespace std;
     char * trip = "abcdefgh";
     unsigned long n = 123456789;
     int i;
     char *temp;
     
     for (i = 1; i< 10; i++)
     {
         cout << left(n,i) << endl;
         temp = left(trip,i);
         cout << temp << endl;
         delete [] temp;
     }
     return 0;
    }
    
    
    
    // 这个函数返回num的前ct位 
    unsigned long left(unsigned long num,unsigned ct)
    {
     unsigned digits = 1;
     unsigned long n = num;
     
     if (ct = 0 || num==0)
         return 0;
     while (n/=10)
         digits++;
     
     if (digits > ct)
     {
     ct = digits - ct;
     while (ct--)
         num /=10;
     return num;
     } 
     else
         return num;
     
    }
    
    // 这个函数返回一个指向新string的指针 
    char *left(const char *str,int n)
    {
     if(n<0){
         n = 0;
     }
     
     char *p = new char[n+1];
     int i;
     for(i=0;i< n&&str[i];i++){
         p[i] = str[i];
     }
     while (i<=n){
         p[i++] = '\0';
     }
     return p;
     } 
    
  5. 当函数基本上执行相同的任务,但是需要使用 不同形式的数据时,可以使用函数重载

函数模板

  1. 函数模板就是通用的函数描述,即使用泛型来定义函数

  2. 泛型可以用具体的类型(比如int或double)来替换,通过将类型作为参数传递给模板,可以使得编译器生成对应类型的函数

  3. 例子

    // 建立一个模板,将类型命名为AnyType,类型名可以是任意的,这里写的是AnyType
    template <typename AnyType>  
    // 下面的方法描述了交换两个AnyType值的算法
    void swap(AnyType &a,AnyType &b){
        AnyType temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    • 模板并不创建任何函数,只是告诉编译器如何定义 函数
    • 在上述例子中,如果需要交换int类型,那么编译器就按模板模式创建相应的函数,然后用int替换掉AnyType
  4. 例子:函数模板例子

    #include <iostream>
    template <typename T>
    void exchange(T &a,T &b);
    
    
    int main()
    {
     using namespace std;
     int i = 10;
     int j = 20;
     
     cout << "原始的i是:" << i<< endl; 
     cout << "原始的j是:" << j<< endl; 
     
     exchange(i,j);
     cout << "交换后的i是:" << i<< endl; 
     cout << "交换后的j是:" << j<< endl;
     
     
     double x = 2.45;
     double y = 5.23;
     
     cout << "原始的x是:" << x << endl; 
     cout << "原始的y是:" << y << endl; 
     
     exchange(x,y);
     cout << "交换后的x是:" << x << endl; 
     cout << "交换后的y是:" << y << endl;
      
     return 0;
    }
    
    template <typename T>
    void exchange(T &a,T &b)
    {
     T temp;
     temp = a;
     a = b;
     b = temp;
    }
    
    • 注意:cpp中有个函数叫swap,如果这里写swap,cpp程序分不清
  5. 可以像重载常规函数定义那样重载模板定义,被重载的模板的函数特征标必须不同

    1. 例子

      #include <iostream>
      
      // 原始的模板 
      template <typename T>
      void exchange(T &a,T &b);
      
      // 新的模板 
      template <typename T>
      void exchange(T *a,T *b, int n);
      
      void Show(int a[]);
      const int LIM = 5;
      
      int main()
      {
       using namespace std;
       int i = 10;
       int j = 20;
       
       cout << "原始的i是:" << i<< endl; 
       cout << "原始的j是:" << j<< endl; 
       exchange(i,j);
       cout << "交换后的i是:" << i<< endl; 
       cout << "交换后的j是:" << j<< endl;
       
       int arr1[LIM] = {0,1,2,3,4};
       int arr2[LIM] = {5,6,7,8,9};
       cout << "原始数组:\n";
       Show(arr1);
       Show(arr2);
       
       exchange(arr1,arr2,LIM);
       cout << "交换之后的数组:\n";
       Show(arr1);
       Show(arr2);
       return 0;
       
       } 
      
      template <typename T>
      void exchange(T &a,T &b){
       T temp;
       temp = a;
       a = b;
       b = temp;
      }
      
      template <typename T>
      void exchange(T a[],T b[],int n){
       T temp;
       for (int i=0;i<n;i++){
           temp = a[i];
           a[i] = b[i];
           b[i] = temp;
       }
      }
      
      void Show(int a[]){
       using namespace std;
       cout << a[0] << a[1] <<"/";
       cout << a[2] << a[3] << "/";
       for (int i=4;i < LIM ;i++){
           cout <<a[i];
       }
       cout << endl;
      }
      
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容