【C++基础(四)】内联函数和auto关键字

简介: 【C++基础(四)】内联函数和auto关键字

💓博主CSDN主页:杭电码农-NEO💓


⏩专栏分类:C++初阶之路


🚚代码仓库:NEO的学习日记🚚


🌹关注我🫵带你学习C++

  🔝🔝



1. 前言

本章重点:

本节着重讲解内联函数的概念
和使用方法,并且介绍auto关键字,
拓展一个C++的范围for(只做了解)


2. 内联函数概念

基本概念:

  • 被inline修饰的函数被称为内联函数
  • 编译器会在编译时将内联函数展开
  • 展开后,没有函数调用建立栈帧的开销
  • 内联函数可以提升程序运行效率

举例说明:

inline int Add(int left, int right)
{
  return left+right;
}

这就是一个内联函数
它的汇编代码可以简单看一下:

函数栈帧的创建与销毁中可知

调用一个函数,开辟栈帧时需要call指令

而这里并没有call指令出现

可见内联函数和普通函数确实有不同

对比说明:普通函数

int Add(int left, int right)
{
  return left+right;
}

它的汇编代码如下:

很明显这里使用了call指令


3. 内联函数的特性

特性:

  1. inline是一种以空间换时间的做法
    如果编译器将函数当成内联函数处理
    在编译阶段,会用函数体替换函数调用

缺陷:可能会使目标文件变大
优势:减少调用开销,提高运行效率


  1. inline对于编译器而言只是一个建议
    若一个函数代码很长
    则编译器不会将它变成内联

在《C++prime》中曾这样写到:


  1. 一般来说,函数代码在10行及以内时
    这时编译器会将它优化为内联函数
    有些编译器是在30行以内

综上所述:

定义函数为内联时
应当检查函数代码行数是否足够少


  1. 内联函数的定义和声明不能分开
    因为inline被展开后
    就没有函数地址了,链接时会找不到

内联函数的一些性质可以
在某些函数使用宏替换的地方
将函数定义为内联,也是同样的效果


4. auto关键字

在学习C++到后期的时候

经常会遇见类似于下面这种代码:

__list_iterator<InputTterator>::iterator it = tmp.begin();
• 1

这段代码看起来非常难理解

但事实上它和定义一个整型是一个意思

就是在定义一个变量

你可能会问:这和auto有啥关系?

auto是一个类型,类似于int,char

但是这个类型是由编译器自己推导出来的

什么意思?,举个例子:

int a = 10;
auto b = a;
auto c = 'a';

由于a是int类型的,将a的值赋值给b
编译器就推导出b的类型也是int
同理可得,c的类型就是char

了解了auto的用法后,来化简代码:

__list_iterator<InputTterator>::iterator it = tmp.begin();
//化简后
auto it = tmp.begin();

这两句代码意思相同
这极大的方便了我们的使用!


5. auto的使用规则

5.1 对指针和引用的区别

  1. 对指针来说*可有可无

请看以下代码:

int x = 10;
auto a = &x;
auto* b = &x;

a的类型是int*,此时的auto是int*

b的类型是int*,此时的auto是int

所以对于对象是指针来说

在使用auto时加不加*都无所谓

  1. 对引用来说必须加上&

请看以下代码:

int x = 10;
auto& c = x;
auto d = x;

c的类型是int的引用,此时的auto是int

d的类型是int,此时的auto是int

假设你想定义一个引用变量

请务必加上引用&符号


5.2 一行多次定义的场景

当在同一行声明多个变量时这些变量
必须是相同的类型,否则编译器将会报错
因为编译器实际只对第一个类型进行推导
然后用推导出来的类型定义其他变量

比如:

auto a = 1, b = 2; //没问题
auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同

事实上,当第一个变量被推导成int后
第二个变量默认也是int.
但是int类型不能存放double类型的值


5.3 auto无法使用的场景

  1. auto无法作为函数参数
void TestAuto(auto a)
{
  //...
}

此处编译器无法对a的实际类型进行推导

  1. auto无法用于声明数组
int a[] = {1,2,3};
auto b[] = {4,5,6};

感觉上,数组中都是整型

那么auto应该会自动识别为整型

但是实际上这样做是不行的,详情请看:

英文文献


6. 基于范围的for循环

C++11中支持这样遍历数组:

int arr[] = {1,2,3,4,5,6};
for(auto e : arr)
{
  cout<<e <<" ";
}

其中的for循环的框架就叫做范围for

它可以这样理解:

并且范围for是可读可写的!

int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
{
   e *= 2;
}

只需要将e的类型变为引用
就可以修改数组中元素

注:中间的:是范围for的规定写法,没有特殊意义

注意:与普通循环类似
可以用continue来结束本次循环
也可以用break来跳出整个循环


7. 总结以及拓展

本节的所有内容旨在为后面的C++
学习打基础,C++学习一环紧扣一环
环环都不能掉队!

拓展:

是不是感觉C++的范围for非常神奇?
但是实际上它是一个非常笨比的实现
它依赖一个叫迭代器的东西

底层实现上
必须有一个自定义函数叫begin()才能
满足范围for,就算你实现的功能和begin
函数一样,但是名字不一样
也不支持范围for,比如Begin

虽然C++后期的学习也会提到范围for

但是大家有兴趣可以提前了解

详情可以参考这篇文章:

C++ 中不同类型的基于范围的 for 循环迭代器


🔎 下期预告:类和对象(上) 🔍



相关文章
|
4月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
191 0
|
8月前
|
安全 编译器 程序员
C++ noexcept 关键字的关键作用
`noexcept` 关键字在 C++ 中扮演着重要角色,通过正确使用 `noexcept`,可以提升程序的性能、增强代码的可读性和安全性,并且有助于编译器进行优化。在编写 C++ 代码时,应仔细考虑每个函数是否应该声明为 `noexcept`,以充分利用这一特性带来的优势。通过本文的介绍,希望开发者能够更好地理解和应用 `noexcept` 关键字,从而编写出更加高效、健壮的 C++ 程序。
267 8
|
10月前
|
安全 编译器 C++
C++ `noexcept` 关键字的深入解析
`noexcept` 关键字在 C++ 中用于指示函数不会抛出异常,有助于编译器优化和提高程序的可靠性。它可以减少代码大小、提高执行效率,并增强程序的稳定性和可预测性。`noexcept` 还可以影响函数重载和模板特化的决策。使用时需谨慎,确保函数确实不会抛出异常,否则可能导致程序崩溃。通过合理使用 `noexcept`,开发者可以编写出更高效、更可靠的 C++ 代码。
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
179 1
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
137 0
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
116 0
|
6月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
243 12
|
7月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
144 16
|
8月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)