【C++学习手札】-引用与内联函数以及C++中对const拓展详解(超详细!)

2023-10-19 01:20

本文主要是介绍【C++学习手札】-引用与内联函数以及C++中对const拓展详解(超详细!),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

                                      食用指南:本文在有C基础的情况下食用更佳

                                      🔥这就不得不推荐此专栏了:C语言

                                      🍀内联函数前置知识:宏函数

                                      ♈️今日夜电波:Episode 33—She Her Her Hers

                                                               1:11 ━━━━━━️💟──────── 4:17
                                                                        🔄   ◀️   ⏸   ▶️    ☰

                                     💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


一、C++中的const

        C语言中的const

        1、const修饰全局变量num 变量名只读 内存空间在文字常量区(只读)、不能通过num的地址修改空间内容。
        2、const修饰局部变量data 变量名只读 内存空间栈区(可读可写),可以通过data地址 间接的修改空间内容。

        栗子:

extern const int num;//用于外部其他文件num的声明const int sum = 100;//只读的全局变量 内存放在文字常量区(内存空间只读)void text()
{const int dat = 100;//局部只读变量 内存在栈区(内存可读可写)//内存可读可写的例子:int* p = (int*) & dat;*p = 200;//此处就将dat修改为200
}

        C++中的const

        首先,我们先理解一个符号表的概念,符号表是一个用于存储程序中所有变量、函数和其他标识符信息的数据结构。它包含了每个标识符的名称、类型、作用域和存储位置等信息。他在编译和链接过程中起到了关键的作用。

        而我们在C++中使用const定义变量时,这个变量可以看成是一个常量,如果他是一个基础的类型,系统不会给他开辟空间而是会把先放入到符号表当中,在对这个数据取地址时,系统才会给他开辟空间。是不是很绕口?请看下面这个图你就明白了。

         对此,你对const定义的基础类型存放有了一定的了解,请继续看下面这个例子

	//1、c++中 对于基础类型 系统不会给dat开辟空间 dat放到符号表中const int dat = 10;//dat = 100;//err 只读cout << "dat = " << dat << endl;//2、c++中当 对dat 取地址的时候 系统就会给dat开辟空间int* p = (int*)&dat;*p = 200;cout << "*p = " << *p << endl;//空间内容修改成功 200cout << "dat = " << dat << endl;//data 还是10为啥?

        很明显的看到,正如上面所写道的,改变*p并不会改变dat的值,改变的是所开辟的空间内存的值!

        注意:上面所述都是在const修饰为基础类型的情况下的!

        那在其他情况下又会如何呢?

        在C++中,当 以变量的形式 初始化 const修饰的变量 系统会为其开辟空间 或者 自定义数据类型(结构体、对象)  系统会分配空间!

        栗子:

struct Person
{int num;char name[32];
};void test4(){//3、当以变量的形式 初始化 const修饰的变量 系统会为其开辟空间int b = 200;const int a = b;//系统直接为a开辟空间 而不会把a放入符号表中int *p = (int*)&a;* p = 3000;cout << "*p = " << *p << endl;//3000cout << "a = " << a << endl;//3000//4、const 自定义数据类型(结构体、对象) 系统会分配空间const Person per = { 100,"lucy" };//per.num = 1000;//errcout << "num = " << per.num << ", name = " << per.name << endl;//100 lucyPerson * p1 = (Person*)&per;p1-> num = 2000;cout << "num = " << per.num << ", name = " << per.name << endl;//2000 lucy
}


二、引用 

        什么是引用?

        引用可以用于访问已存在的变量或对象。通过引用,可以通过不同的名称访问同一个变量,而不是创建副本。引用通常用于函数参数传递和函数返回值。说白了就是给已有变量取个别名。

        引用的结构:

        &和别名 结合 表示引用

         一个简单的栗子:

int num = 10;int &a = num;

        注意:这里的&不是表示取地址,而是引用的标志。

        几个需要注意的规则:

                1、给某个变量取别名 就定义某个变量
                2、从上往下替换

                3、引用必须初始化
                4、引用一旦初始化 就不能再次修改别名

        栗子:

void test5()
{int a = 20;int& b = a;cout << "a=" << a << endl;b = 200;cout << "b= " << b << endl;cout << "a地址:" << &a << endl;cout << "b地址:" << &b << endl;}

                        

        由此可见a就是b,b就是a,b只不过是a的另外一个名字。 

引用的定义模板(如有错误,请踢一脚作者)

要取别名的类型( &(原来变量名的位置,直接替换别名))巴拉巴拉 = 要取别名的变量
        引用-数组
void test6(){int arr[5] = {10,20,30,40,50};//需求:给arr起个别名int (&my_arr)[5] = arr;//my_arr就是数组arr的别名int i=0;for(i=0;i<5;i++){cout<<my_arr[i]<<" ";}cout<<endl;}

 引用在函数中的应用

        作为参数
void swap(int* a, int* b)
{int temp = *a;*a = *b;*b = temp;
}void swap2(int& a, int& b)
{int temp = a;a = b;b = temp;
}void test7()
{int n1 = 114, n2 = 514;//swap(&n1, &n2);swap2(n1, n2);//swap==swap2cout << "n1=" << n1 << " n2=" << n2 << endl;//n1=514 n2=114
}

        作为返回值

//引用作为函数的返回值类型int& my_data(void){int num = 100;return num;//err 函数返回啥变量 引用就是该变量的别名//函数的返回值是引用时 不要返回局部变量}int& my_data1(void){static int num = 200;return num;//ok}void test8(){//ret是别名 ret是num的别名int &ret = my_data();//cout<<"ret = "<<ret<<endl;//非法访问内存int &ret1 = my_data1();//ret1是num的别名cout<<"ret = "<<ret1<<endl;}

        注意:函数返回值作为左值 那么函数的返回值类型必须是引用

常引用

        ->常量的引用

void test9(){//给常量10取个别名 叫num//int &针对的是int ,10是const int类型//const int 针对的是const int, 10是const int类型const int &num = 10;cout<<"num = "<<num<<endl;//10}

引用的本质 

        引用的本质在 c++内部实现是一个指针常量。

        Type& ref = val; // Type* const ref =&val;
        c++编译器在编译过程中使用常指针作为引用的内部实现, 因此引用所占用的空间
大小与指针相同, 只是这个过程是编译器内部实现, 用户不可见。


三、内联函数

         🍀内联函数前置知识宏函数

        宏函数(带参数的宏)的缺点:
        第一个在c中也会出现,宏看起来像一个函数调用,但是会有隐藏一些难以发现的错误。
第二个问题是c++特有的,预处理器不允许访问类的成员,也就是说预处理器宏不能用作类
的成员函数。


        内联函数:

        内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,可以进行参数,返回值类型的安全检查,又可以作为成员函数。内联函数是一个真正的函数。函数的替换 发生在编译阶段。

        任何在类内部定义的函数自动成为内联函数。

        注意:内联仅仅只是给编译器一个建议, 编译器不一定会接受这种建议, 如果你没有将函
数声明为内联函数, 那么编译器也可能将此函数做内联编译。 一个好的编译器将会
内联小的、 简单的函数。

        总的来说:内联函数是宏函数的优化!

        栗子:

 #define SUB(x,y) x-yinline int sub(int x, int y) {return x - y;
}void test10()
{cout << "(define)x-y= " << SUB(5, 1) << endl;//(define)x-y= 4cout << "(inline)x-y= " << sub(5, 1) << endl;//(inline)x-y= 4
}

        这样看起来内联函数是不是同宏函数一模一样呢?请看下面这个例子:

#define MUT(x,y) x*yinline int mut(int x, int y) {return x * y;
}void test10()
{cout << "(define)x-y= " << MUT(5-2, 2) << endl;// 5-2*2cout << "(inline)x-y= " << mut(5-2, 2) << endl;// 3*2
}

        实际上,我们是可以将内联函数看作普通的函数的,但是内联函数有以下几个限制条件:
 

不能是内联函数的情况

        1、 函数包含静态变量。

        2、for、while带有循环形式的函数。

        3.、递归调用本身的函数。

        4、包含复杂语句的函数。

        5、函数体不能过于庞大 不能对函数进行取址操作

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


                感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!

                             

                                                                给个三连再走嘛~

这篇关于【C++学习手札】-引用与内联函数以及C++中对const拓展详解(超详细!)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/236366

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof