鱼C论坛

 找回密码
 立即注册
查看: 3170|回复: 1

[技术交流] 不是从零开始的c++学习笔记(003)——缺省参数,内联,动态内存分配,引用

[复制链接]
发表于 2017-6-9 21:32:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1.函数参数的默认值(缺省参数)

1.1概念
定义或者声明一个函数时,可以给这个函数的参数指定一个默认的初始值,调用这个函数的时候,如果不给这个参数传入值,则使用默认值。如果给这个参数传入值 则会替代掉默认值。

  1. #include <iostream>
  2. using namespace std;
  3. int getmax(int x=10,int y=100);
  4. int main()
  5. {
  6.         cout << getmax() << endl;//100
  7.         cout << getmax(200) << endl;//第一个参数赋值200,第二个默认值100
  8.         cout << getmax(55,66) << endl;//66
  9. }
  10. int getmax(int x,int y)
  11. {
  12.     return x>y?x:y;
  13. }
复制代码


1.2参数默认值使用的注意事项
1.2.1如果函数的某一个参数有默认值,那么该参数右边的所有参数都必须有默认值(靠右原则)
  1. int getmax(int x=10,int y);//错误
复制代码


1.2.2不要和重载形成调用冲突


  1. getmax(int x,int y=200);
  2. getmax(int x,int y,int z);

  3. cout << getmax(100) << endl;//调用第一个getmax
  4. cout << getmax(200,100) << endl;//调用第一个getmax
  5. cout << getmax(55,66,77) << endl;//调用第二个getmax

  6. //但是如果把getmax(int x,int y,int z);稍微更改
  7. getmax(int x,int y,int z=0);

  8. cout << getmax(55,66) << endl;//那么这时候无法确定会调用哪一个getmax

复制代码


1.2.3函数的默认值是在编译阶段阶段解决的,因此只能用常量、常量表达式或者全局变量等非局部化的数值作为函数的默认值

  1. int a = 100;
  2. void fishc(int a = g,int b = 100+23);
  3. void fishc(int a,int b =a);//错误
复制代码


1.2.4当函数的声明和实现分开时,则需要在声明中指定默认值,实现中不要再指定默认值。

  1. #include <iostream>
  2. using namespace std;
  3. //int getmax(int x,int y);错误
  4. int getmax(int x=10,int y=100);
  5. int main()
  6. {
  7.         cout << getmax() << endl;//100
  8.         cout << getmax(200) << endl;//第一个参数赋值200,第二个默认值100
  9.         cout << getmax(55,66) << endl;//66
  10. }
  11. //int getmax(int x=10,int y=100)错误
  12. int getmax(int x,int y)
  13. {
  14.     return x>y?x:y;
  15. }
复制代码


2.内联函数(inline)

2.1为什么要引入内联
函数底层调用时会在内存中不断跳转,会造成一定的时间和空间方面的开销,从而影响程序执行效率,特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来说,解决其效率问题尤为重要。引入内联函数实际上就是为了解决这一问题。

2.2类比C语言中的宏函数(带参宏)
  1. #include <iostream>
  2. using namespace std;
  3. #define  GETMAX(X,Y)  ((X)>(Y)?(X):(Y))

  4. int main()
  5. {
  6.         cout << GETMAX(100,200) << endl;
  7.         int  x=123;
  8.         int  y=345;
  9.         cout << GETMAX(x,y) << endl;
  10.         cout << GETMAX(y,x) << endl;

  11. }
复制代码


2.3原理
内联就是用函数已被编译好的二进制代码,替换对该函数的调用指令,更通俗点说,就是在编译时,请求编译器把函数的代码复制到调用位置。请求成功,就使用空间换取时间,请求不成功 则成为普通函数调用。

内联在保证函数特性的同时,避免了函数调用的开销,通过牺牲代码空间,赢得了运行时间

内联通常被视为一种编译优化策略

2.4具体运用
在需要内联的函数前面加上inline

  1. #include <iostream>
  2. using namespace std;

  3. inline int  getmax(int x,int y)
  4. {
  5.     return x>y?x:y;
  6. }
  7. int main()
  8. {
  9.         cout << getmax(100,200) << endl;
  10. }
复制代码


2.5隐式内联和显式内联

2.5.1隐式内联
若函数在类或结构体的内部直接定义,则该函数会被自动优化为内联函数
2.5.2显式内联
若在函数定义前面加上inline关键字,可以显式告诉编译器,该函数被希望优化为内联函数

2.6内联的适用条件和一些问题
2.6.1使用条件
内联会使可执行文件的体积和进程代码的内存变大,因此
小函数,频繁调用,适合内联
大函数,稀少调用,不适合内联
递归函数,无法实现内敛
2.6.2一些问题
inline关键字仅仅代表一中对函数实施内联优化的期望,但该函数是否真的会被处理为内联函数,还要由编译器的优化策略决定

3.c++中的动态内存分配

3.1操作符
c++提供了new和delete操作符,分别用于动态内存的分配和释放

3.2分配单个变量对应的内存
  1. 类型 *指针名 = new 类型名;
  2. 类型 *指针名 = new 类型名();
  3. 类型 *指针名 = new 类型名(值);//初始化的值
  4. /* 释放堆内存 */
  5. delete  指针名;
复制代码
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int *p = new int;
  6.     *p = 10;
  7.     cout << *p << endl;
  8.     delete p;
  9.    
  10.     p = new int(100);
  11.     cout << *p << endl;
  12.     delete p;
  13.    
  14.     return 0;
  15. }
复制代码


3.3分配多个变量对应的内存,类似数组的方式进行分配与释放
申请n个类型变量对应的堆内存
类型 *指针名=new 类型[n];     
/* 释放这块堆内存 */
delete[]  指针名;
  1. int *p = new int[4]{1,2,3,4};
  2. /*字符数组一个只能初始化一个字符,而且此时指针保存的并不是整个字符串的首地址
  3. 而只是第一个字符的地址,所以拿指针进行打印,只能打印出来一个字符

  4. delete[] p;
复制代码


3.4定位内存分配(了解)
  1. char  data[100];
  2. int   *pdata=new (data)int[25];
复制代码

pdata 的内存指向栈中,不用考虑释放问题
并且pdata 和 data的地址是相同的

3.5内存分配的一些细节
3.5.1某些c++实现,用new操作符动态分配内存时,会在数组首元素前面多分配4或8个字节,用以存放数组的长度,new操作符所返回的地址是数组首元素地址,而非分配内存的首地址

3.5.2如果new操作符的地址直接交给delete处理,将导致无效指针(invalidate pointer)异常,使用delete[]操作符会将交给它的地址向低地址方向偏移4或8个字节,避免了无效指针异常的发生

3.5.3重析构
不能通过delete操作符释放已经释放过的内存
  1. int* p = new int;
  2. delete p;
  3. delete p;//核心转储
  4. //标准库检测到重析构(double free)异常后,将进程杀死,并转储进程映像
复制代码


3.5.4不建议与C语言中的动态内存分配函数混用,它会带来不可预知的问题。

4.引用(reference)

4.1概念
引用实际上就是一个变量的别名

4.2语法
/* 引用必须初始化 */
类型&   变量名=变量;
/* 引用一旦初始化之后,在引用的生命期内就不能更改引用的对象*/
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.         int   x=100;
  6.         int&  rx=x;
  7.         cout << &x << endl;
  8.         cout << &rx << endl;
  9.         rx=1001;
  10.         cout << x << endl;
  11.         x=10001;
  12.         cout << rx << endl;
  13.         int   y=111;
  14.         int&  rrx=rx;
  15.         /* 这不是引用y 只是把y的值复制给 rrx */
  16.         rrx=y;
  17.         rrx=121;
  18.         cout << y << endl;

  19. }
复制代码


4.3引用的应用

4.3.1引用型的函数参数
以前c当中,有过用函数交换两个变量的值,可以通过指针值传递,那么现在可以使用引用传递了
引用传递:参数的类型是引用类型
  1. #include <iostream>
  2. using namespace std;
  3. void  myswap(int x,int y)//无法交换
  4. {
  5.         int temp=x;
  6.         x=y;
  7.         y=temp;
  8. }
  9. void  myswap2(int * x,int * y)//指针传递
  10. {
  11.         int temp=*x;
  12.         *x=*y;
  13.         *y=temp;
  14. }
  15. void  myswap3(int& x,int& y)//引用传递
  16. {
  17.         int temp=x;
  18.         x=y;
  19.         y=temp;
  20. }


  21. int main()
  22. {  
  23.         int  x=10;
  24.         int  y=20;
  25.         // myswap2(&x,&y);
  26.         myswap3(x,y);
  27.         cout << x << '/' << y << endl;
  28. }
复制代码


通过引用传递参数,形参只是实参的别名而非副本,这就避免了从实参到形参的对象复制,这对于具有复杂数据结构的参数类型而言意义非常

4.3.2常量无法作为引用型参数传递,但是如果引用参数前加const就可以使用常量
如果函数内部不对数据进行修改则建议对参数写成const引用,这样除了防止修改,还增强了函数的兼容。

  1. void  printNum(const int& x)//void  printNum(int& x),如果函数是这样,程序报错
  2. {
  3.     cout << x << endl;
  4. }
  5. int main()
  6. {  
  7.         printNum(200);
  8.         const  int z=100;
  9.         printNum(z);
  10. }
复制代码


4.3.3引用类型的返回值
函数的返回值一般用来做右值,如果希望做左值,可以使用指针,或者使用引用。
注意不要返回局部变量的引用。可以返回static全局变量,堆中的数据,成员变量,引用型参数。

  1. #include <iostream>
  2. using namespace std;
  3. int*   getmax(int* x,int* y)//用指针方法让函数返回值做左值
  4. {
  5.     return  *x>*y?x:y;
  6. }
  7. int&   getmax(int& x,int& y)//引用的方法
  8. {
  9.     return  x>y?x:y;
  10. }
  11. int&   getNum()
  12. {
  13.     // static int  x=155;
  14.         int *x=new int(168);
  15.     return  *x;
  16. }
  17. int main()
  18. {
  19.     int  z=100;
  20.     int  x=10;
  21.     int  y=20;
  22.     // *(getmax(&x,&y))=z;       
  23.         getmax(x,y)=z;
  24.         cout << y << endl;
  25.         cout << getNum() << endl;
  26. }
复制代码


4.4引用的底层实现
通过上面的代码,应该容易推断出,引用的底层实现就是指针

4.5引用和指针的联系与区别 (待补充)

下期预告:c++中的类型转换,类和对象,类的定义与实例化,构造函数与初始化表
新坑预告:明天可能会发win32程序开发相关的笔记,求支持

评分

参与人数 2荣誉 +1 鱼币 +10 收起 理由
抹语 + 1 感谢楼主无私奉献!
小甲鱼 + 10 支持楼主!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-1-4 16:23:20 | 显示全部楼层
感谢,刚学C++,一直看到缺省参数,终于弄明白了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-11 10:40

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表