zoukankan      html  css  js  c++  java
  • c++ primer 第六章总结

    1.传值与传引用

    形参与实参:

    (1)形参一定会被初始化

    (2)形参名可选,如果没有形参名那么我们就不能使用该形参,所以一般都会有形参名。出现未命名的形参,一般就是说我们在该函数中用不到它,但还是必须给他提供实参。

    传值与传引用

    传值:

    (1)发生值的拷贝
    (2)形参与实参是两个不同的东西
    (3)对形参的操作不会影响实参

    传引用

    (1)传引用是它对应实参的一个别名
    (2)对它操作就是在对实参操作

    该注意的几点:

    (1)使用传引用来避免拷贝。如果实参很大或者根本就不支持拷贝,只能用传引用。

    (2)函数不需要改变引用参数的值就用const来修饰。尽可能使用const

    2.管理指针形参

    (1)使用标记指定数组长度。如:c语言用’’来表示一个字符数组的结束

    void print(const char *str)
    {
        if(str)    //指针非空
        {
            while(*str)
                cout <<   *str++  << "  " ;
            cout << endl ;
        }
    }

    (2)使用标准库规范

    传递头指针与尾后元素的指针(既然是尾后指针,那么就不能解引用)

    #include<iostream>
    using namespace std;
    void print(const int *beg,const int *end)
    {
        while(beg != end)
        {
            cout << *beg++ << endl ;
        }
    }
    int main(void)
    {
        int a[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
        print(begin(a),end(a));  //调用形式
    }

    (3)传递一个表明数组大小的形参。即 void print(const int a[],int size); //size 表示数组有size个元素

    3.可变参

    想象一个场景。我要实现一个功能相同的函数,但是我每次要给他传的参数不相同。那么就会用到可变参了!

    (1)initializer_list 标准库类型。要求实参类型相同 ,常用操作与vector相同,但有一点不同的就是 initializer_list 中的值是常量,不可改变。其实就相当于用const修饰了一下。

    #include<iostream>
    #include<initializer_list>
    using namespace std;
    
    void err_msg(initializer_list<string> list1,int a = 0)    //可变参
    {
        cout << "a== " << a << endl ;
        for(auto i=list1.begin();i != list1.end();++i)
            cout << *i << "  " ;
        cout << endl ;
    }
    int  sum(initializer_list<int> const& list2)
    {
        int sum = 0;
        for(auto i: list2)
            sum+=i;
        return sum;
    }
    int main(void)
    {
        err_msg({"liu","sheng","xi"});
        err_msg({"rnejn","nbrm"});
        err_msg({});
        cout << "sum == "  << sum({1,2,3,4,5,6,7,8,9}) << endl ;
    }

    运行截图;

    这里写图片描述

    (2)如果实参类型不同->>特殊的函数:可变参数模板

    (3)省略符形参

    注意事项:

    (1)只用于与C函数交互的接口

    (2)大多数类类型的对象在传递的过程中都无法正确拷贝

    (3)省略符形参只能出现在形参列表的最后一个位置

    有下列两种形式:

    void foo ( parm_list , …);
    void foo ( … );

    第一种形式为特定数目的形参提供了声明。在这种情况下,当函数被调用时,对于与显示声明的形参相对应的实参进行类型检查,而对于与省略符对应的实参则暂停类型检查。在第一种形式中,形参声明后面的逗号是可选的。

    (4)每个参数的类型可以不同,也可以相同

    (5)与无参函数有别

    (6)省略号的优先级别最低,所以在函数解析时,只有当其它所有的函数都无法调用时,编译器才会考虑调用省略号函数的

    (7)在传递与取用的时候,要类型一一对应

    #include <stdio.h> 
    #include <stdarg.h> 
    void ArgFunc(const char *str ... ) 
    { 
        va_list ap; 
    
        int n = 3; 
        char *s = NULL; 
        int d = 0; 
        double f = 0.0; 
    
        va_start(ap, str); // 注意!这里第二个参数是本函数的第一个形参 
    
        s = va_arg(ap, char*); 
        //s = va_arg(ap, int);  //编译不通过,会报错。所以说在传递与取用的时候,要类型一一对应
    
        d = va_arg(ap, int); 
    
        f = va_arg(ap, double); // 浮点最好用double类型,而不要用float类型;否则数据会有问题 
    
        va_end(ap); 
    
        printf("%s is %s %d, %f 
    
     ", str, s, d, f); 
    } 
    int main(void) 
    { 
        ArgFunc("The answer", "Hello", 345, 788.234); 
    } 

    运行截图:

    这里写图片描述

    参考学习:参考学习1

    参考学习:参考学习2

    4.局部与整体

    不要返回局部对象的引用和指针。也就是说局部的东西会在局部(一般是函数)执行完就会被释放,返回的时候要考虑这一点。

    5.默认实参

    一种形参但在多次调用中都反复使用同一个值,可传参也可不传参,不传参就使用默认值,传参就使用所传入的实参。一般在函数声明中指定,放在合适的头文件中。

    void err_msg(initializer_list<string> list1,int a = 0)    //a 就是一个默认参数

    6.内联函数

    对于较小的函数(为了程序的“好看性”),我们可能真正执行的就那么一小会,但是对于函数的调用可能花费很长的时间。也就是说函数调用花费的时间会比函数真正起作用的时间要长的多,如果频繁调用程序效率就会非常低下,(类比:线程池等)那么我们就会用到内联函数来解决这个问题了

    内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。

    内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。内联说明只是向编译器发出一个请求,编译器可以选择忽略这个请求

    #include<iostream>
    using namespace std;
    /*
     * struct timespec {
    2 time_t tv_sec;  //seconds
    3 long tv_nsec; // nanoseconds   納秒
    4 };
    */
    timespec diff(timespec start, timespec end)
    {
        timespec temp;
        if ((end.tv_nsec-start.tv_nsec)<0) {
            temp.tv_sec = end.tv_sec-start.tv_sec-1;
            temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
        } else {
            temp.tv_sec = end.tv_sec-start.tv_sec;
            temp.tv_nsec = end.tv_nsec-start.tv_nsec;
        }
        return temp;
    }
    inline void  fun1(int temp)
    {
        for(int i = 0 ;i != 10000 ;++i)
            ;
    
    }
    int main(void)
    {
        timespec time1, time2;
    
        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);   // 一个进程的时间
    
       for(int i= 0;i< 400000;++i)
            fun1(10);   //将这里进行内联与非内联的替换
    
        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
        cout<< "秒数是:"<< diff(time1,time2).tv_sec<< " 纳秒数是 :"<< diff(time1,time2).tv_nsec<<endl;
    }

    运行截图:

    这里写图片描述

    由结果可以看出,内联函数的确是有一点功效的。

    7.constexpr函数

    不想写了–>>constexpr函数

    8. 函数指针

    (1)void (*fun)(int a,int b); //fun就是一个函数指针

    注意事项:不存在智能转换

    这里写图片描述

    #include<iostream>
    using namespace std;
    int compare_0(const int &a,const int &b)
    {
        return a-b;
    }
    double compare_1(const int &a,const int &b)
    {
        return a-b;
    }
    int main(void)
    {
        int (*p)(const int &,const int &);
        p=compare_0;  //不存在智能转换
        cout << p(12,11) << endl ; 
    }

    运行截图:

    这里写图片描述

    (2)函数类型

    参考学习:参考学习

  • 相关阅读:
    读取列表下标
    字典dict详解
    使用mysql的长连接
    oauth授权协议的原理
    安装性能测试工具:sysbench和使用apache的ab
    发送邮件出现问题
    获取用户的真实ip
    清理代码的阅读笔记
    开发中三个经典的原则
    要干大事就不能把面子看得太重
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335313.html
Copyright © 2011-2022 走看看