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

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

一、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;//空间内容修改成功 200
  cout << "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;//3000
  cout << "a = " << a << endl;//3000
  //4、const 自定义数据类型(结构体、对象) 系统会分配空间
  const Person per = { 100,"lucy" };
  //per.num = 1000;//err
  cout << "num = " << per.num << ", name = " << per.name << endl;//100 lucy
  Person * 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==swap2
  cout << "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-y
inline int sub(int x, int y) {
  return x - y;
}
void test10()
{
  cout << "(define)x-y= " << SUB(5, 1) << endl;//(define)x-y= 4
  cout << "(inline)x-y= " << sub(5, 1) << endl;//(inline)x-y= 4
}

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

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

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

 

不能是内联函数的情况

       1、 函数包含静态变量。

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

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

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

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

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


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

相关文章
|
2月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
56 0
|
17天前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
12 1
|
19天前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
19天前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
23天前
|
程序员 C++ 开发者
C++入门教程:掌握函数重载、引用与内联函数的概念
通过上述介绍和实例,我们可以看到,函数重载提供了多态性;引用提高了函数调用的效率和便捷性;内联函数则在保证代码清晰的同时,提高了程序的运行效率。掌握这些概念,对于初学者来说是非常重要的,它们是提升C++编程技能的基石。
19 0
|
2月前
|
安全 编译器 C++
C++入门 | 函数重载、引用、内联函数
C++入门 | 函数重载、引用、内联函数
30 5
|
1月前
|
C语言 C++
C++(三)内联函数
本文介绍了C++中的内联函数概念及其与宏函数的区别。通过对比宏函数和普通函数,展示了内联函数在提高程序执行效率方面的优势。同时,详细解释了如何在C++中声明内联函数以及其适用场景,并给出了示例代码。内联函数能够减少函数调用开销,但在使用时需谨慎评估其对代码体积的影响。
|
3月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
28 3
|
3月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
3月前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用