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)函数类型

参考学习:参考学习

原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335313.html