C++---day03

目录: 
1. C的提高 1-131P 时间七天 
2. C++的基础 132-286P 时间八天 
3. C++的提高 287-378P 时间五天 
4. C/C++的数据结构 379-482P 时间五天 
5. C/C++的设计模式基础 483-540P 时间三天

 

视频资料:https://www.bilibili.com/video/av27904891?from=search&seid=10891514449061956870

 


P151  引用的本质剖析

引用的意义

1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针

2)引用相对于指针来说具有更好的可读性和实用性

引用本质思考

#include <iostream>
using namespace std;
//1.单独定义的引用时,必须初始化,说明很像一个常量
void main01()
{
    
    const int c1=10;
    int a=10;
    int &b=a;//b很像一个常量
    printf("&a:%d\n",&a);
    printf("&b:%d\n",&b);//a和b均是同一块内存空间的门牌号
    system("pause");
    return;
}

//2.普通引用有自己的空间
struct Teacher
{
    char name[64];//64
    int age;//4

    int &a;//4  0 很像指针所占的内存大小
    int &b;//4  0
};
void main()
{
    printf("sizeof(Teacher):%d\n",sizeof(Teacher));//76
    system("pause");
    return;
}
//3. 引用的本质
void modifyA(int &a1)
{
    a1=100;
}
void modifyA2(int *const a1)
{
    *a1=200;//*实参的地址,去间接的修改实参的值
}


void main03()
{
    int a=10;
    //1
    modifyA(a);//执行这个函数调用的时候,不需要取a的地址
    printf("a:%d\n",a);

    //2
    modifyA2(&a);//如果是指针需要手工取实参的地址
    printf("a:%d\n",a);
    system("pause");
    return;
}

//4. 间接赋值
void modifyA3(int *p)
{
    *p=300;//3. *p
}
void main04()
{
    int a=10;
    int *p=NULL;//间接赋值的三个条件 定义两个变量

    p=&a;
    *p=100;
    {
        *p=200;
    }
    modifyA3(&a);//2. 建立关联
}

 

引用的本质

1)引用在C++中的内部实现是一个常指针

      Type& name <-->Type* const name

2C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。

3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏

4) 对比间接赋值成立的三个条件

      1、定义两个变量 (一个实参一个形参)

      2、建立关联 实参取地址传给形参

      3、*p形参去间接的修改实参的值

 

引用结论

1)引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一

     //当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)

2)当我们使用引用语法的时,我们不去关心编译器引用是怎么做的

      当我们分析奇怪的语法现象的时,我们才去考虑c++编译器是怎么做的


 P152  函数返回值是引用(引用当左值)

C++引用使用时的难点:

  当函数返回值为引用时

    若返回栈变量

    不能成为其它引用的初始值

    不能作为左值使用

  若返回静态变量或全局变量

    可以成为其他引用的初始值

    即可作为右值使用,也可作为左值使用

C++链式编程中,经常用到引用,运算符重载专题

#include <iostream>
using namespace std;

int getA1()
{
    int a;
    a=10;
    return a;
}
//返回a的本身
int& getA2()
{
    int a;//如果是返回栈上的引用有可能会有问题
    a=10;
    return a;
}
int* getA3()
{
    int a;
    a=10;
    return &a;
}
void main()
{
    int a1=getA1();

    int a2=getA2();

    int &a3=getA2();
    printf("a1:%d\na2:%d\na3:%d\n",a1,a2,a3);
    system("pause");
    return;
}

 

 函数当左值

//返回变量的值
int g1()
{
    static int a=10;
    a++;
    return a;
}
//返回变量本身
int& g2()
{
    static int a=10;
    a++;
    return a;
}
void main()
{
    g1()=100;
    g2()=100;
    system("pause");
}

出现错误

//----函数当左值
//返回变量的值
int g1()
{
    static int a=10;
    a++;
    return a;
}
//返回变量本身
int& g2()
{
    static int a=10;
    a++;
    printf("a:%d\n",a);
    return a;
}
void main()
{
    //g1()=100;
    g2()=100;//函数返回值是一个引用,并且当左值
    g2();

    int c=g2();//函数返回值是一个引用,并且当右值
    system("pause");
}

输出结果


 P153  小结

1、命名空间

2、输入和输出流

3、面向过程和面向对象

4、类的抽象,类的实例化

  成员函数

5、类的扩展:类型加强,函数加强,异常加强

6、namespace命名空间:

      当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;

      使用using namespace std;

7、实用性增强:定义变量更加自由

8、register增强

9、struct类型增强

10、C++中所有的变量和函数都必须有类型

11、新增Bool类型关键字

12、三目运算符增强

  在C语言中,表达式返回的是变量的值

  在C++中,表达式返回的是变量的本身

13、const

  C++符号表机制,当碰到常量声明时,会将常量放入符号表中

  C语言中的const变量是只读变量,有自己的存储空间

  C++中的const常量可能分配存储空间,也可能不分配存储空间

    当const常量为全局,并且需要在其他文件中使用

    当使用&操作符取const常量的地址

14、引用

  对一段连续的内存空间取一个别名

  引用是一个常量指针

  函数当左值必须返回一个引用


 P154  指针的引用

 需要重新理解。。。。

 

 

 

 注:VS注释快捷键:Ctrl+K,Ctrl+C

        取消注释快捷键:Ctrl+K,Ctrl+U


 P155  常引用

使用变量初始化const引用 

#include <iostream>
using namespace std;
void main()
{
    //普通引用
    int a=10;
    int &b=a;
    printf("b:%d\n",b);

    //常引用
    int x=20;
    const int &y=x;//常引用 让变量引用只读属性,不能通过y去修改x了
    //y=21;

    //常引用 初识化 分为2种情况
    //1. 用变量初始化 常引用
    {
        int x1=30;
        const int &y1=x1;//用x1变量去初始化 常引用
    }
    //2. 用字面量去初始化 常引用
    {
        const int a=10;//c++编译器把a放在符号表中
        //int &m=41;//普通引用 引用一个字面量
        //引用就是给内存取多个别名
        const int &m=42;//c++编译器会分配内存空间
    }

    system("pause");
    return;
}

 


 P156  inline内联函数

C++中推荐使用内联函数替代宏代码片段

C++中使用inline关键字声明内联函数

说明1

    必须inline int myfunc(int a, int b)和函数体的实现,写在一块

 

说明2  

    内联函数在最终生成的代码中是没有定义的

    C++编译器直接将函数体插入在函数调用的地方

    内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)

 

说明3

    C++编译器不一定准许函数的内联请求!

 

说明4

 

    内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型等)

 

    内联函数是对编译器的一种请求,因此编译器可能拒绝这种请求

 

    内联函数由 编译器处理,直接将编译后的函数体插入调用的地方

 

    宏代码片段 由预处理器处理 进行简单的文本替换,没有任何编译过程

 

说明5

 

    现代C++编译器能够进行编译优化,因此一些函数即使没有inline声明,也可能被编译器内联编译

 

    另外,一些现代C++编译器提供了扩展语法,能够对函数进行强制内联

 

    如:g++中的__attribute__((always_inline))属性

 

 

 

说明6

    C++中内联编译的限制:

    不能存在任何形式的循环语句    

    不能存在过多的条件判断语句

    函数体不能过于庞大

    不能对函数进行取址操作

    函数内联声明必须在调用语句之前

 

结论:
1)内联函数在编译时直接将函数体插入函数调用的地方

2)inline只是一种请求,编译器不一定允许这种请求

3)内联函数省去了普通函数调用时压栈,跳转和返回的开销 

//带参数的宏
#define MYFUNC(a, b) ((a) < (b) ? (a) : (b))  

inline int myfunc(int a, int b) 
{
    return a < b ? a : b;
}

int main()
{
    int a = 1;
    int b = 3;
    //int c = myfunc(++a, b);  //a=2,b=3,c=2
    int c = MYFUNC(++a, b);  //(++a) < (b) ? (++a) : (b)-->a=3,b=3,c=3

    printf("a = %d\n", a); 
    printf("b = %d\n", b);
    printf("c = %d\n", c);

    system("pause");
    return 0;
}

 


P157  函数参数相关扩展

默认参数

C++中可以在函数声明时为参数提供一个默认值,

当函数调用时没有指定这个参数的值,编译器会自动用默认值代替

#include <iostream>
using namespace std;

void myPrint(int x=3)
{
    cout<<"x:"<<x<<endl;
}
//2. 一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值
void myPrint2(int m,int x=3,int y=4)
{
    cout<<"x:"<<x<<endl;
}
void main()
{
    //1.若填写参数,使用填写的,不填写默认
    myPrint(4);
    myPrint();
    system("pause");
    return;
}

 

函数占位参数

//函数占位参数,函数调用时必须写够参数
void func1(int a,int b,int)
{
    cout<<"a:"<<a<<" b:"<<b<<endl;
}
void main()
{
    //func1(1,2);
    func1(1,2,3);
    system("pause");
    return;
}

 

默认参数和占位参数

void func2(int a, int b,int =0)
{
    cout<<"a:"<<a<<" b:"<<b<<endl;
}
void main()
{
    func2(1,2);
    func2(1,2,3);
    system("pause");
    return;
}

输出结果:

 


 P158  函数的重载

1、函数重载概念

函数重载(Function Overload)

用同一个函数名定义不同的函数

当函数名和不同的参数搭配时函数的含义不同

 

2 、函数重载的判断标准

函数重载至少满足下面的一个条件:

    参数个数不同

    参数类型不同

    参数顺序不同

3、函数返回值不是函数重载的判断标准

   实验1:调用情况分析;实验2:判断标准

 

 

 

函数重载的调用准则

编译器调用重载函数的准则

  将所有同名函数作为候选者

  尝试寻找可行的候选函数

  精确匹配实参

  通过默认参数能够匹配实参

  通过默认类型转换匹配实参

  匹配失败

  最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。

  无法匹配所有候选者,函数未定义,编译失败。

 

函数重载的注意事项

  重载函数在本质上是相互独立的不同函数(静态链编)

  重载函数的函数类型是不同的

  函数返回值不能作为函数重载的依据

  函数重载是由函数名和参数列表决定的。

#include <iostream>
using namespace std;

void myPrint(int a)
{
    printf("a:%d\n",a);
}
void myPrint(char *p)
{
    printf("p:%s\n",p);
}
void myPrint(int a,int b)
{
    printf("a:%d\n",a);
    printf("b:%d\n",b);
}
/*
//   返回值不是函数重载的判断
int myPrint(int a,int b)
{
    printf("a:%d\n",a);
    printf("b:%d\n",b);
}
*/

//1. 当函数名和不同的参数搭配时函数的含义不同
//2. 函数重载的判断标准
//   名称 参数 返回值
//   名称相同,参数不一样(个数/类型)
//3. 返回值不是函数重载的判断
//4. 重载函数调用标准
//     

void main()
{
    myPrint(1);
    myPrint("aaafssfs");
    myPrint(1,2);
    system("pause");
    return;
}

 函数默认参数 和 函数重载在一起

void myfunc(int a,int b,int c=0)
{
    printf("a:%d  b:%d  c:%d\n",a,b,c);
}
void myfunc(int a,int b)
{
    printf("a:%d  b:%d \n",a,b);
}
void main()
{
    //myfunc(1,2);//函数调用时会产生二义性
    system("pause");
    return;
}

 


 P159  函数重载和指针在一起

函数重载与函数指针

  当使用重载函数名对函数指针进行赋值时

  根据重载规则挑选与函数指针参数列表一致的候选者

  严格匹配候选者的函数类型与函数指针的函数类型

#include <iostream>
using namespace std;

void myfunc(int a)
{
    printf("a:%d\n",a);
}
void myfunc(char *p)
{
    printf("p:%s\n",p);
}
void myfunc(int a,int b)
{
    printf("a:%d\n",a);
    printf("b:%d\n",b);
}
void myfunc(char *p1,char *p2)
{
    printf("p1:%d\n",p1);
    printf("p2:%d\n",p2);
}
//函数指针
//声明一个函数类型
//void myfunc(int a,int b)
typedef void (myTypeFunc)(int a,int b);//int

//声明一个函数指针类型
typedef void (*myPTypeFunc)(int a,int b);//声明一个指针的数据类型
//myPTypeFunc fp=NULL;通过函数指针类型 定义了一个函数指针

//定义一个函数指针变量
void (*myVarPFunc)(int a,int b);
void main()
{
    //myTypeFunc *myfuncp=NULL;//定义一个函数指针,这个指针指向函数的入口地址
    myPTypeFunc fp;//定义了一个函数指针变量
    fp=myfunc;
    //fp(1);
    fp(1,2);
    /*{
        char buf1[]="aaa";
        char buf2[]="bbb";
        fp(buf1,buf2);

    }*/
    system("pause");
    return;
}

 

posted @ 2019-02-14 16:44  洛水卿卿  阅读(318)  评论(0编辑  收藏  举报