C++学习(二)

内联函数(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;
}

运行结果正常
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值