概述
C++ 内联函数
内联函数是C++为了提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将他们组合到编译器中。
编译过程的最终产品是可执行程序---由一组机器语言指令组成。程序在运行时,操作系统会将这些指令载入到计算机内存中,因此每条指令都有特定的内存地址,稍后计算机将逐步执行这些指令,有时(如有循环或分支语句时),将跳过一些指令,向前或向后跳到特定地址。常规函数调用也使程序跳到另一个地址 (函数的地址),并在函数结束时返回。下面更详细地介绍这一过程的典型实现。执行到函数调用指令时, 程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标 记函数起点的内存单元,执行函数代码(也许还需将返回值放入到寄存器中),然后跳回到地址被保存的指 令处(这与阅读文章时停下来看脚注,并在阅读完脚注后返回到以前阅读的地方类似)。来回跳跃并记录跳 跃位置意味着以前使用函数时,需要一定的开销。
而对于内联函数来讲是将函数调用直接替换为函数代码块
这样,就无需跳转出去再次跳转回来,但是这样做的代价是:
需要占用更多的内存
假设有十处函数调用,函数本身内容也比较大,那么内联函数带来的空间上的牺牲是时间上的小利弥补不了的。应当有选择的使用内联函数。另外如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程的很小一部分。如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分时间。另一方面,由于这个过程相当快,因此尽管节省了该过程的大部分时间,但节省的时间绝对值并不大,除非被经常调用。
总的来说,内联函数将函数调用替换为函数体,以此来减短函数跳转的时间,但是这种方法可能会牺牲较大的内存,应该有选择的使用内联函数。
内联函数的用法
为使用内联函数:
- 在函数声明时在函数声明前面加上关键字
inline
- 在函数定义时在函数定义前面加上关键字
inline
- 或者将声明和定义放在一起
另外,要注意 :内联函数不能进行递归!!
程序员在请求将函数定义为内联函数时,编译器不一定会允许这种要求,如果函数过大或者注意到这个函数是递归函数,那么编译器则不会将此函数作为内联函数;而有的编译器没有内联函数这一特性。
eg:
#include<iostream>
using namespace std;
inline double square(double x){return x*x;}
int main(void)
{
double x=1.0;
x=square(x)*2;
x=square(x+x)*2;
cout<<x;
while(cin.get()!=EOF);
return 0;
}
内联与宏
或许我们会发现,内联函数与预定义宏相似
inline double square(double x){return x*x;}
#define Square(x) ((x)*(x))
预定义宏是通过文本替换来实现的,宏不能够按值传递。比如说:
square(x++);
Square(x++);
两者方式是不一样的,在使用预定义宏的时候可以考虑使用内联函数,可以将内联函数与泛型函数结合对数据类型进行控制。
引用变量
引用是已定义的变量的别名,通过将引用变量作为参数,函数将使用原始数据,而不是其副本。
创建引用变量
int rate;
int& rat=rate;
&作为类标识符的一部分,int&表示rat为指向int类型rate的引用,上述声明表示,他们指向相同的值和内存单元。rat就是rate的别名,对rat的操作就相当于作用到rate身上。二者指向的地址是相同的。
注意: 引用在声明时必须初始化,而不能先声明再初始化。引用一旦与某一个变量建立起联系,那么将誓死效忠于它,不能够中途改变引用指向的量。
将引用用于函数参数
#include <iostream>
using namespace std;
void fswap(int, int);
void qswap(int *, int *);
void rswap(int &, int &);
int main(void)
{
int a = 1, b = 100;
int &c = a;
int &d = b;
cout << 'a' << " " << 'b' << endl;
cout << a << " " << b << endl;
fswap(a, b);
cout << a << " " << b << endl;
qswap(&a, &b);
cout << a << " " << b << endl;
rswap(c, d);
cout << a << " " << b << endl;
while (cin.get() != EOF)
;
return 0;
}
void fswap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
void qswap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void rswap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
三种传递方式
- 按值传递
- 指针传递
- 按引用传递
按值传递会使用初始值的副本而不改变原来的值。
指针传递与按引用传递正确使用会改变原来的值。
编写程序时需要注意这几点,来确定是否真的希望改变原来的值,对于后面两种表示来讲,如果不希望改变,可以添加const
限定符。
临时变量、引用参数和
const
const
如果实参与引用参数不匹配,c++将生成临时变量。
const
引用时,C++才允许这样做
但是以前不是这样的。下面将介绍什么情况下C++生成临时变量,以及为何对const
引用的限制是合理的。
如果引用的参数是const
,将在以下情况生成临时变量:
- 实参的类型正确,但不是左值;
- 实参的类型不正确,但可以转化为合适的类型。
左值是什么呢?左值参数是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和解除引用的指针都是左值。非左值包括字面常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式。在C语言中,左值最初指的是可出现在赋值语句左边的实体,但这是引入关键字const之前的情况。现在,常规变量和const 变量都可视为左值,因为可通过地址访问它们。但常规变量属于可修改的左值,而const 变量属于不可修改的左值。
注意: 如果函数调用的不是左值或者相应的const
引用参数类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值按值传递给该匿名变量,并让参数来应用该变量。
应尽可能使用
const
const
将引用参数声明为常量数据的引用的理由有三个:
-
使用const可以避免无意中修改数据的编程错误;
-
使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
-
使用const引用使函数能够正确生成并使用临时变量。
因此,应尽可能将引用形参声明为const。
右值引用
C++11新增了另一种引用——右值引用,可以指向右值,是使用&&
来声明的。
右值引用的主要目的是让库设计人员能够提供有些操作的更有效地实现。
之前的引用称之为左值引用。
第十八章将讨论使用右值引用实现移动语义。
将引用用于结构
void f1(const T& a);
void f2(T& a);
T& f3(T& a,const T& b);
T是一个已经定义的结构,由上可见,参数类型可以是结构,const
型结构,结构的引用,返回类型也可以是结构的引用和结构。
对于返回类型为引用
传统函数返回机制与函数参数按值传递机制差不多:计算return
关键字后面的表达时后,复制这个值到一个临时变量,如果需要使用再进行传递。而如果使01.用返回类型为引用,那么调用的函数就相当于是变量的别名,无需创建临时变量即可调用。
注意: 不要返回函数终止时不再存在的内存引用单元。如下面所示:
const T& f1(T& a)
{
T b;
b=a;
return b;
}
当函数结束时创建的结构b将会被释放内存,不再存在。同样的,也应该避免返回指向临时变量的指针。为避免这种问题,可以有两种方法:
- 返回一个作为参数传递给函数的引用。
- 使用
new
来分配新的存储空间,返回指向该内存空间的指针或者引用。
另外,可以使用const
来修饰返回值,返回值不会被赋值或更改。
引用也可以用于类对象
按照前面的形式即可。
关于对于何时使用引用参数的论述
有一部分关于对象、继承和引用的文段没有整理下来,或许将来学习相关内容后能够更好地理解。
new
来分配新的存储空间,返回指向该内存空间的指针或者引用。
另外,可以使用const
来修饰返回值,返回值不会被赋值或更改。
引用也可以用于类对象
按照前面的形式即可。
有一部分关于对象、继承和引用的文段没有整理下来,或许将来学习相关内容后能够更好地理解。
最后
以上就是包容画笔为你收集整理的C++ 内联函数与引用变量的全部内容,希望文章能够帮你解决C++ 内联函数与引用变量所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复