不是从零开始的c++学习笔记(003)——缺省参数,内联,动态内存分配,引用
1.函数参数的默认值(缺省参数)1.1概念
定义或者声明一个函数时,可以给这个函数的参数指定一个默认的初始值,调用这个函数的时候,如果不给这个参数传入值,则使用默认值。如果给这个参数传入值 则会替代掉默认值。
#include <iostream>
using namespace std;
int getmax(int x=10,int y=100);
int main()
{
cout << getmax() << endl;//100
cout << getmax(200) << endl;//第一个参数赋值200,第二个默认值100
cout << getmax(55,66) << endl;//66
}
int getmax(int x,int y)
{
return x>y?x:y;
}
1.2参数默认值使用的注意事项
1.2.1如果函数的某一个参数有默认值,那么该参数右边的所有参数都必须有默认值(靠右原则)
int getmax(int x=10,int y);//错误
1.2.2不要和重载形成调用冲突
getmax(int x,int y=200);
getmax(int x,int y,int z);
cout << getmax(100) << endl;//调用第一个getmax
cout << getmax(200,100) << endl;//调用第一个getmax
cout << getmax(55,66,77) << endl;//调用第二个getmax
//但是如果把getmax(int x,int y,int z);稍微更改
getmax(int x,int y,int z=0);
cout << getmax(55,66) << endl;//那么这时候无法确定会调用哪一个getmax
1.2.3函数的默认值是在编译阶段阶段解决的,因此只能用常量、常量表达式或者全局变量等非局部化的数值作为函数的默认值
int a = 100;
void fishc(int a = g,int b = 100+23);
void fishc(int a,int b =a);//错误
1.2.4当函数的声明和实现分开时,则需要在声明中指定默认值,实现中不要再指定默认值。
#include <iostream>
using namespace std;
//int getmax(int x,int y);错误
int getmax(int x=10,int y=100);
int main()
{
cout << getmax() << endl;//100
cout << getmax(200) << endl;//第一个参数赋值200,第二个默认值100
cout << getmax(55,66) << endl;//66
}
//int getmax(int x=10,int y=100)错误
int getmax(int x,int y)
{
return x>y?x:y;
}
2.内联函数(inline)
2.1为什么要引入内联
函数底层调用时会在内存中不断跳转,会造成一定的时间和空间方面的开销,从而影响程序执行效率,特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来说,解决其效率问题尤为重要。引入内联函数实际上就是为了解决这一问题。
2.2类比C语言中的宏函数(带参宏)
#include <iostream>
using namespace std;
#defineGETMAX(X,Y)((X)>(Y)?(X):(Y))
int main()
{
cout << GETMAX(100,200) << endl;
intx=123;
inty=345;
cout << GETMAX(x,y) << endl;
cout << GETMAX(y,x) << endl;
}
2.3原理
内联就是用函数已被编译好的二进制代码,替换对该函数的调用指令,更通俗点说,就是在编译时,请求编译器把函数的代码复制到调用位置。请求成功,就使用空间换取时间,请求不成功 则成为普通函数调用。
内联在保证函数特性的同时,避免了函数调用的开销,通过牺牲代码空间,赢得了运行时间
内联通常被视为一种编译优化策略
2.4具体运用
在需要内联的函数前面加上inline
#include <iostream>
using namespace std;
inline intgetmax(int x,int y)
{
return x>y?x:y;
}
int main()
{
cout << getmax(100,200) << endl;
}
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分配单个变量对应的内存
类型 *指针名 = new 类型名;
类型 *指针名 = new 类型名();
类型 *指针名 = new 类型名(值);//初始化的值
/* 释放堆内存 */
delete指针名;
#include <iostream>
using namespace std;
int main()
{
int *p = new int;
*p = 10;
cout << *p << endl;
delete p;
p = new int(100);
cout << *p << endl;
delete p;
return 0;
}
3.3分配多个变量对应的内存,类似数组的方式进行分配与释放
申请n个类型变量对应的堆内存
类型 *指针名=new 类型;
/* 释放这块堆内存 */
delete[]指针名;
int *p = new int{1,2,3,4};
/*字符数组一个只能初始化一个字符,而且此时指针保存的并不是整个字符串的首地址
而只是第一个字符的地址,所以拿指针进行打印,只能打印出来一个字符
delete[] p;
3.4定位内存分配(了解)
chardata;
int *pdata=new (data)int;
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操作符释放已经释放过的内存
int* p = new int;
delete p;
delete p;//核心转储
//标准库检测到重析构(double free)异常后,将进程杀死,并转储进程映像
3.5.4不建议与C语言中的动态内存分配函数混用,它会带来不可预知的问题。
4.引用(reference)
4.1概念
引用实际上就是一个变量的别名
4.2语法
/* 引用必须初始化 */
类型& 变量名=变量;
/* 引用一旦初始化之后,在引用的生命期内就不能更改引用的对象*/
#include <iostream>
using namespace std;
int main()
{
int x=100;
int&rx=x;
cout << &x << endl;
cout << &rx << endl;
rx=1001;
cout << x << endl;
x=10001;
cout << rx << endl;
int y=111;
int&rrx=rx;
/* 这不是引用y 只是把y的值复制给 rrx */
rrx=y;
rrx=121;
cout << y << endl;
}
4.3引用的应用
4.3.1引用型的函数参数
以前c当中,有过用函数交换两个变量的值,可以通过指针值传递,那么现在可以使用引用传递了
引用传递:参数的类型是引用类型
#include <iostream>
using namespace std;
voidmyswap(int x,int y)//无法交换
{
int temp=x;
x=y;
y=temp;
}
voidmyswap2(int * x,int * y)//指针传递
{
int temp=*x;
*x=*y;
*y=temp;
}
voidmyswap3(int& x,int& y)//引用传递
{
int temp=x;
x=y;
y=temp;
}
int main()
{
intx=10;
inty=20;
// myswap2(&x,&y);
myswap3(x,y);
cout << x << '/' << y << endl;
}
通过引用传递参数,形参只是实参的别名而非副本,这就避免了从实参到形参的对象复制,这对于具有复杂数据结构的参数类型而言意义非常
4.3.2常量无法作为引用型参数传递,但是如果引用参数前加const就可以使用常量
如果函数内部不对数据进行修改则建议对参数写成const引用,这样除了防止修改,还增强了函数的兼容。
voidprintNum(const int& x)//voidprintNum(int& x),如果函数是这样,程序报错
{
cout << x << endl;
}
int main()
{
printNum(200);
constint z=100;
printNum(z);
}
4.3.3引用类型的返回值
函数的返回值一般用来做右值,如果希望做左值,可以使用指针,或者使用引用。
注意不要返回局部变量的引用。可以返回static全局变量,堆中的数据,成员变量,引用型参数。
#include <iostream>
using namespace std;
int* getmax(int* x,int* y)//用指针方法让函数返回值做左值
{
return*x>*y?x:y;
}
int& getmax(int& x,int& y)//引用的方法
{
returnx>y?x:y;
}
int& getNum()
{
// static intx=155;
int *x=new int(168);
return*x;
}
int main()
{
intz=100;
intx=10;
inty=20;
// *(getmax(&x,&y))=z;
getmax(x,y)=z;
cout << y << endl;
cout << getNum() << endl;
}
4.4引用的底层实现
通过上面的代码,应该容易推断出,引用的底层实现就是指针
4.5引用和指针的联系与区别 (待补充)
下期预告:c++中的类型转换,类和对象,类的定义与实例化,构造函数与初始化表
新坑预告:明天可能会发win32程序开发相关的笔记,求支持 感谢,刚学C++,一直看到缺省参数,终于弄明白了
页:
[1]