C++_primer查漏补缺

C++_PRIMER 整理总结

地址

数组的地址

数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址

p1.jpeg p2.jpeg

运算符

运算符区别

箭头成员运算符(->) 配合结构体指针使用

.运算符配合结构体名称使用

ps是指向结构体的指针,则*ps就是被指向的值--结构本身

*ps是一个结构,(*ps).price是该结构的price成员


结合

指针与运算符的结合

p3.jpeg p4.jpeg

指针(包括数组名)加1,实际上是加上了一个与指针指向的类型的长度相等的值.

数组与指针对应的优势:将数组地址作为参数可以节省复制整个数组所需的时间和内存.

P214 整理 数组与指针


const

常量指针与指针常量的区别

p6.jpeg

指针指向的内容,不能通过指针来进行改动.但是能通过其他方式改动值.

p7.jpeg

此时pt指针的值可以修改,但是只能指向一个变量.

const在*前面,表示不能通过pt指针修改值,const指针在*后面,标志pt指针不能修改指向

出现const int *const pt的情况,即不能修改const指针的值,又不能修改其指向.


函数指针

函数指针

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>

using namespace std;

const double *f1(const double *ar,int n);
const double *f2(const double ar[],int n);
const double *f3(const double ar[],int n);

int main(void){

    double av[3] = {1112.3,1542.6,2227.9};

    //part1
    //函数指针 p1
    const double *(*p1)(const double *,int) = f1;
    auto p2 = f2;
    cout<<"part1----------------"<<endl;
    cout<<"Address        Value"<<endl;
    cout<<(*p1)(av,3)<<" : "<<*(*p1)(av,3)<<endl;
    cout<<p2(av,3)<<" : "<<*p2(av,3)<<endl;

    //part2
    //pa(pb) 指针构成的数组
    const double *(*pa[3])(const double *,int) = {f1,f2,f3};
    auto pb = pa;
    cout<<"part2----------------"<<endl;
    for (int i=0;i<3;i++)
        cout<<pa[i](av,3)<<" : "<<*pa[i](av,3) <<endl;

    //part3
    //pc(pd) 指针,指向函数指针构成的数组
    cout<<"part3----------------"<<endl;
    auto pc = &pa;
    const  double *(*(*pd)[3])(const double *,int) = &pa;
    cout<<"Address        Value"<<endl;
    cout<<(*pc)[0](av,3)<<" : "<<*(*pc)[0](av,3)<<endl;
    const double *pdb = (*pd)[1](av,3);
    cout<<pdb<<" : "<<*pdb<<endl;
    cout<<(*pd)[2](av,3)<<" : "<<*(*pd)[2](av,3)<<endl;
    return 0;
}
//指针表示法
const double *f1(const double *ar,int n)
{
    return ar;
}
//数组表示法
const double *f2(const double ar[],int n)
{
    return ar + 1;
}

const double *f3(const double ar[],int n)
{
    return ar + 2;
}

运行结果

p8.jpeg

区别于混淆

(*pa[2])(av,3) *pa[2](av,3)的区别

(*pa[2])(av,3)

根据结合性 []优先级高于*,优先与pa结合

pa是数组,pa[2]是数组的第三个元素,这个元素是一个函数指针,指向f3的函数指针,*pa[2]是f3函数本身,f3(av,3)则是返回其第三个元素的地址

结果:第三个元素的地址

*pa[2](av,3)

根据结合性pa[2](av,3)先结合 再与指针结合

pa[2]是指向f3的指针,结合后是f3(av,3),重点对于函数指针,f3()*f3()是完全一致的,f3(av,3)计算了数组中第三个元素的地址,再结合*,就是第三个元素返回的的值

结果:第三个元素的值


引用

引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名.这种传递参数的方法称为按引用传递.按引用传递允许被调用的函数能够访问调用函数中的变量.

如果声明将引用指定为const,c++将在必要时生成临时变量.

使用引用参数的主要原因:

  1. 能够修改调用函数中的数据对象
  2. 通过传递引用而不是整个数据对象,可以提高程序的运行速度

按值传递的指导原则:

p5.jpeg

传递在使用时的技巧:

  1. 如果传递的是数组,就用指针
  2. 如果传递的是类,就用引用
  3. 如果传递的是结构体,指针和引用都可以
  4. 如果要传递一个基本类型,这个值不想修改就按值传,如果想修改就用指针.

右值引用

能用取地址值&操作的 就是左值,不能的是右值.

如果想使用左值引用,但是等号右侧的值,无法取地址操作,使用const常引用.

1
const int &d = 10;

只能通过引用来读取数据,不能通过引用来修改数据.

c++11引入了右值引用的概念 两个&&符号定义右值引用.

1
int &&x = 10;

重载解析

对于函数重载/函数模板和函数模板重载,C++的策略

从最佳到最差的匹配顺序:

  1. 完全匹配,但常规函数优先于模板
  2. 提升转换
  3. 标准转换
  4. 用户定义的转换,如类声明中定义的转换
updatedupdated2022-03-172022-03-17