内联函数(inline function)
直接将函数的调用转换为函数定义的代码,而不进行函数在内存上的开辟和回收
在函数代码比较少和调用次数多的情况下使用可以优化程序运行
#include <iostream>
using namespace std;
inline int production(int a,int b){
return a*b;
}
int main(){
cout<<production(3,4)<<endl;
getchar();
return 0;
}
运行结果其实和不加inline的结果一致
同时inline添加的位置,可以在函数的声明也可以放在函数的实现,两个位置当然也是正确的
#include <iostream>
using namespace std;
int production(int a,int b);//这里加上inline也可以
int main(){
cout<<production(3,4)<<endl;
getchar();
return 0;
}
//下面inline也可以不写,放在上面的声明中
inline int production(int a,int b){
return a*b;
}
这里也介绍一下功能类似的宏的写法,宏也是将某个东西先前定义,main函数执行中遇到这个东西就替换成你定义的东西,比如我们可以定义
#include <iostream>
using namespace std;
#define pi 3.14//宏定义pi=3.14
#define times(a,b) ((a)+(b))//宏定义,后面遇到times(a,b)就替换为a+b
int production(int a,int b);//声明了一个乘法函数
int main(){
cout<<times(3,pi)<<endl;//pi就替换成了3.14,time(3,pi)最终换成了3+3.14
cout<<production(3,4)<<endl;//此处替换代码为3*4
getchar();
return 0;
}
inline int production(int a,int b){
return a*b;
}
运行结果如我们所料
但是要注意,宏没有检测代码的功能,也就是说,如果宏的定义的内容代码是错的,但你没有调用过这个宏,或者说直到调用宏的时候才会报错。而内联函数,由于本质还是函数,如果函数体不符合C++语法就会报错。
当然由于内联函数和宏本质是不同的,所以我们有时候也会得到不同的结果,我们通过一个例子来看一下两者运行的本质
#include <iostream>
using namespace std;
#define times(a) ((a)+(a))//宏定义times(a) 为a+a
inline int sum(int a);//内联函数定义sum结果是a+a
int main(){
int a=1,b=1;//为了防止++后的数值变化,我们声明了a,b两个变量,并都赋值1
cout<<"times's result is "<<times(a++)<<endl;//此处调用了宏定义的times
cout<<"sum's result is "<<sum(b++)<<endl;//此处调用了内联函数
getchar();
return 0;
}
inline int sum(int a){
return a+a;
}
运行结果,可能和大家想的不同,两个结果是不一样的
为什么times运行结果是3,而sum函数运行结果是2呢?
我们分析一下
编译器执行到times(a++)时,根据宏翻译成了a++ + a++,第一个a++完成后,其实第一个位置返回的是a的原始值,也就是1,所以此刻式子变成1 + a++(此时a=2);接着执行第二个a++,返回的值是a的原始值2,而a此时变成3;也就是最终times(a++)变成了1+2=3(此时a=3)
而当编译器运行到sum(b++),b++使得b=2,但是返回值是1,也就是将1传给了函数体部分的变量a,此时a=1,然后执行a+a自然等于2
这里有个小问题,如果我们使用的是++a和++b那么
#include <iostream>
using namespace std;
#define times(a) ((a)+(a))
inline int sum(int a);
int main(){
int a=1,b=1;
cout<<"times's result is "<<times(++a)<<endl;//注意这里是++a
cout<<"sum's result is "<<sum(++b)<<endl;//注意这里是++b
getchar();
return 0;
}
inline int sum(int a){
return a+a;
}
可能运行的结果和我们想的不同,也就是 ++a + ++a=6这个出乎我们意料
我们先解释第二个sum内联函数的结果,++b运行后,返回值是2,此时b也是2,传给参数a的值也是2,所以a+a就是2+2=4,和我们大家想的一样。
我们看第一个出乎我们意料的问题
原因可能是这样的,编译器首先处理了两次++c,所以导致返回值是3,且c出栈时的值也是3,然后执行两者的加法运算,最终3+3=6(可能我自己理解有误)
或者可能是入栈顺序 +、 ++c、 ++c;出栈顺序++c、 ++c这时c=3,然后+出栈运算c+c=6(可能我理解的有误,应该需要数据结构的知识才能明白)
引用(reference)(一)浅讲
先复习一下C语言中,指针的用法
稍稍讲解一下下面代码
#include <iostream>
using namespace std;
int main(){
int a=1;//申请了一个名字为a的变量,开辟了一个地址,并且地址存入a
int *pa=&a;//这里int *表示申请一个指针变量,名叫pa,存入pa变量的值是a的地址
//&a表示获取a变量所在的地址
cout<< pa <<endl;//打印一下pa变量的所存的值,也就是a的地址
*pa = 30;//这时候*是一个运算符
//也就是把pa变量所存的地址对应的变量a的存储值替换为30
cout<< a <<endl;//我们看一下a的值现在变化为多少
getchar();
return 0;
}
运行结果正是,a所在的地址即pa指针变量储存的值,和a改变后的值30
我们可以认为引用是给一个变量起了一个别名。我们分别写了各种数据类型的引用。不同的段落用//***…分开了,表示谈论不同的数据类型。代码很长但是很简单,难得我写了这么长的码,我这么懒的人,真的不容易哈哈哈
#include <iostream>
using namespace std;
//定义了一个枚举,列举a、b、c、d
enum ABCD{
a,
b,
c,
d
};
//定义了一个结构体Student,包含一个变量score
struct Student
{
int score;
};
int main(){
int a=1;//定义了一个普通变量a,赋值为1
int &ra=a;//定义了一个引用变量ra,是a的别名
ra=4;
cout<<"int a is "<<a<<endl;//看一下a的值是否改变
//***********************************************
enum ABCD alphabet;
//定义枚举类型ABCD的枚举变量名字为alphabet
enum ABCD &ralphabet = alphabet;
//定义枚举变量alphabet的引用别名ralphabet
ralphabet = c;//为ralphabet赋值
cout<<"enum alphabet is "<< alphabet<<endl;
//看一下alphabet储存了什么
//***********************************************
struct Student stu;//命名结构体Student为stu
struct Student &rstu = stu;//结构体stu,我们引用别名为rstu
rstu.score = 100;//为rstu中的score变量赋值100
cout <<"stu.score is " << stu.score <<endl;
//我们看一下stu.score中储存值是多少
//***********************************************
int c=1;//定义普通变量c
int b=3;//定义普通变量b
int *p = &c;//定义指针变量p,并赋值a的地址
int *&rp = p;//把指针变量p,引用别名rp
//分开看这句代码int *是声明指针变量,&rp是引用变量名rp
rp = &b;//rp的值被覆盖为b的地址
*rp = 10;//rp所存地址的变量的值改为10
cout<<"int b changes to "<< b<<endl <<"rp is "
<< rp <<endl <<"address of b is "<< &b << endl;
//打印b的值,rp的值(b的地址),和b的地址(rp的值)
//***********************************************
int list[]={3,4,5};//创建数组list
int (&Rlist)[3] = list;//给list数组引用别名Rlist
Rlist[1] = 9;//更改数组Rlist中的第二个值
cout<< "second value of list changes to "
<< list[1] <<endl;
//打印list的第二个值
getchar();
return 0;
}
如果我们耐心读完代码,我们应该可以猜到输出结果
总的来讲,
- 引用可以代表被引用的变量,进行各种操作,也就是对引用变量的操作就是对被引用变量的操作处理;
- 同时引用变量的声明和赋值是同时的,也就是在声明一个引用变量后就要写明它引用了哪个变量。同时,一但确定不能更改。
#include <iostream>
using namespace std;
//错误的代码
int main(){
int a = 10;
int b = 20;
int &r = a;
int &r = b;//这是违规的操作,不能更改
// 只写&r = b也是错误的
//写成r = b就变成了赋值含义,也是不能改变被引用变量的
getchar();
return 0;
}
但是一个变量可以对应多个引用变量
#include <iostream>
using namespace std;
int main(){
int a = 10;//变量a赋值10
int &ra = a;//引用变量ra对应a
int &rra = a;//引用变量rra对应a
int &rrra = rra;//看起来引用变量rrra对应rra,但本质是对应a
int &rrrra = rra;//看起来引用变量rrrra对应rra,本质还是对应变量a
rrra = 3;//给任一个变量赋值
//这里写ra=3,rra=3···都是一样的
cout << a + ra +rrrra <<endl;//打印一下他们相互相加
getchar();
return 0;
}
运行结果如我们所料,是9。
在这里a、ra、rra、rrra、rrrra都是一样的,r…a本质都是a的引用,不存在引用的引用。
还有一个问题,其实引用只是给变量起了一些别名而已,地址并不会更改
我们看一下这个例子
#include <iostream>
using namespace std;
int main(){
int a = 10;
int &ra = a;//a的引用变量ra
int *p = &ra;//将ra的地址传给指针变量p
cout << "address of a is " << p << endl
<< "address of a is " << &a <<endl;
//打印p储存的ra的地址,以及打印a的地址
getchar();
return 0;
}
运行结果一定和机智的我们所料一样
需要注意
- 指向引用的指针不存在,因为引用就是被引用变量的别名,上面我们看到了他们的地址都是一样的
- 引用数组也是错误的(
不是上文的数组的引用 这个语言说不清我们上代码吧)
#include <iostream>
using namespace std;
//这是错误的写法
int main(){
int a[] = {10,20};
int &ra[2] = a; //这是错误的写法,
//int (&ra)[2]=a的写法才对
getchar();
return 0;
}
举一个需要引用的例子
比如我们想交换两个变量的值,当然也可以用指针完成
#include <iostream>
using namespace std;
//定义一个交换值的函数
void exchange(int *a,int *b){
//v的地址传给指针a,w的地址传给指针b
int c = *a;
//指针a所存地址对应变量的值给c
*a = *b;
//指针b所存地址对应变量的值
//覆盖指针a所存地址对应变量之前的值
*b = c;//c的值传给指针b所存地址对应变量的值
}
int main(){
int v = 3;
int w = 4;
cout<< "v is "<<v
<< " w is "<<w<<endl;
exchange(&v,&w);//调用函数exchange
//v,w变量的地址传给函数
cout<< "now v is "<<v
<< " w is "<<w<<endl;
getchar();
return 0;
}
运行结果如下
现在我们用引用实现这一功能
#include <iostream>
using namespace std;
//定义一个交换值的函数
void exchange(int &a,int &b){
//变量v的引用(别名)是a
//变量w的引用(别名)是b
//下面三行大家这么聪明就看懂了
int c = a;
a = b;
b = c;
}
int main(){
int v = 3;
int w = 4;
cout<< "v is "<<v
<< " w is "<<w<<endl;
exchange(v,w);//这里可以不用传地址了!
cout<< "now v is "<<v
<< " w is "<<w<<endl;
getchar();
return 0;
}
运行结果正常,我们简化了这个交换值的过程(当然了不使用指针或者引用,直接void exchange(int a,int b){···}这样是不可能写出来的,因为a,b都是临时变量,用完就扔了,交换了a和b没用啊,v和w还是老样子,我懒得写了大家这么聪明自己实现一下就知道不行 )
本博客内容借鉴了C++ primer和小码哥的视频以及其他网络资料
关于++i的问题借鉴https://blog.csdn.net/u014465639/article/details/72812187和小伙伴
PS:我尝试了下面的写法,也是可以的。
#include <iostream>
using namespace std;
int main(){
int a = 1;
int &ra = a;
ra = 3*a;//用被引用变量的值的三倍给引用变量赋值
cout << a <<endl;
getchar();
return 0;
}
运行结果正常