如何在C++中实现内联函数

144 阅读5分钟

在C++中实现内联函数

在程序中采用函数的主要目的之一是保存内存,特别是当一个函数可能被反复调用时。当一个函数被调用时,需要花费很长的时间来执行诸如移位到调用函数的操作。

如果一个函数很短,开销会消耗其执行时间的很大一部分,跳转到调用函数的时间可能比执行该函数的时间还要长。

宏定义;大多被称为宏,是解决这一问题的方法之一。

在C编程语言中,预处理器宏是很常见的,但主要的缺点是它们不是真正的函数。因此,典型的错误检查过程在编译过程中被绕过了。

这个问题在C++中的处理方式是不同的。C++引入了一个新的函数,叫做内联函数,以减少调用小函数的时间。

本文将向读者介绍C++中的内联函数;这是编程中的一个重要领域,并以一个实际演示作为后续。

前提条件

要学习这篇文章,读者应该具备以下条件。

  • 对C++编程语言的理解。
  • 安装了Codeblocks IDE以运行程序。
  • 对C++函数的理解。

什么是内联函数?

内联函数是一个在[调用时]被[扩展成一行的]函数[,可以节省时间]。编译器将相应的函数代码替换为函数调用,[减少了函数调用的开销]。

注意:内联是[对编译器的]一个[请求,而不是一个命令]。编译器可以选择忽略和绕过内联请求。

语法。

Inline function-header
{
function body
}

内联函数的声明和定义必须同时进行。

例子来演示内联函数。

#include <iostream>
using namespace std;
inline int cube(int x)
{
	return x*x*x;
}
int main()
{
	cout << "Our cube is: " << cube(3) << "\n";
	return 0;
} 

输出。

The cube of 3 is: 27

这是一个简单的例子,演示了一个使用inline关键字作为前缀声明的inline function

可以内联使用的函数和类

内联函数也可以在类内定义。所有在类内声明的函数,实际上都是隐式内联的。因此,所有适用于内联函数的约束也适用于此。

如果你需要在类中明确地声明一个内联函数,请在类中这样做,然后在类外用inline关键字定义它。

请看下面的例子。

class x
{
public:
	inline int circle(int x) // use of inline many times
	{
		// This function is inlined by default.
		// function's body
	}
};

上面描述的技术被认为是一种糟糕的编程技术。

将函数原型写在类内,并在函数规范中将其声明为内联,是最有效的编程方法。

举例来说。

class x
{
public:
	int circle(int x); // make a function declaration
};

inline int X::circle(int x) // make advantage of the inline prefix
{

}

这一原则在下面的程序中得到了证明。

#include <iostream>
using namespace std;
class calculation
{
	int x,y,plus,subtract,mult;
	float divi;
public:
	void getValue();
	void addition();
	void subtraction();
	void multiplication();
	void division();
};
inline void calculation :: getValue()
{
	cout << "Enter first value:";
	cin >> x;
	cout << "Enter second value:";
	cin >> y;
}

inline void calculation :: addition()
{
	plus = x+y;
	cout << "Addition of two numbers: " << x+y << "\n";
}

inline void calculation :: subtraction()
{
	subtract = x-y;
	cout << "Difference of two numbers: " << x-y << "\n";
}

inline void calculation :: multiplication()
{
	mult = x*y;
	cout << "Product of two numbers: " << x*y << "\n";
}

inline void calculation ::division()
{
	divi=x/y;
	cout<<"Division of two numbers: "<<x/y<<"\n" ;
}

int main()
{
	cout << "Program using inline function\n";
	calculation m;
	m.getValue();
	m.addition();
	m.subtraction();
	m.multiplication();
	m.division();
	return 0;
}

在该程序中,我们可以看到如何应用第二种技术在类内实现内联函数。

当我们运行上面的程序时,它更有效,表现得更好。

内联可能不被编译器执行的情况。

  • 如果一个函数中存在一个循环。
  • 如果一个函数是递归的。
  • 如果函数中存在静态变量。
  • 如果在一个函数中存在switch命令或goto语句。
  • 如果一个[不返回值的函数]存在一个返回语句。

我们什么时候使用内联函数?

我们可以使用内联函数来满足我们的要求。下面是一些关于何时使用的有益建议。

  • 当对性能有要求时,开发人员会使用内联函数。
  • 我们总是可以使用内联函数而不是宏。
  • 为了隐藏函数的实现细节,开发者建议在有内联函数的类之外使用内联关键字。

使用内联函数时需要记住的几点

  • 我们必须保持内联函数的微小,因为它们更有效率,产生更好的结果。
  • 尽管内联函数提高了效率,但它们不应该用于所有的函数,因为把巨大的函数放在内联中可能会导致代码杂乱,降低效率。
  • 大型函数应该在类声明之外使用范围解析操作符:: ,因为如果我们在类定义中定义它们,它们可能会自动变成内联,从而降低我们的代码效率。

宏的问题是什么?

熟悉C编程语言的读者都知道它采用了宏。所有的宏调用都是由预处理程序直接在宏代码内替换的。

应始终使用内联函数而不是宏。根据C++的设计者Bjarne Stroustrup博士的说法,宏在C++中几乎没有必要,而且宏容易出错。

在C++中使用宏有几个缺点。宏不能访问一个类的私有成员。宏看起来是函数调用,但它们不是。

例如。

#include <iostream>
using namespace std;
class X
{
	int a;
public:
#define MAC(X::a) // error
};

内联函数的参数类型由C++编译器检查,并执行任何必要的转换。预处理器宏不能做到这一点。另外,宏是由预处理器管理的,而[内联函数是由C++编译器管理]的。

诚然,所有在类内声明的函数都是隐式内联的。而且C++编译器会内联调用这些函数。但是如果函数是虚拟的,C++编译器就不会内联它。其原因是,虚函数的调用是在运行时而不是在编译时解决的。

另外要记住的是,只有当[调用函数的时间长于执行函数体的时间]时,使函数内联才有效。

一个内联函数没有效果的例子。

inline void display()
{
	cout << "value of X = " << X << endl;
}

前面提到的函数需要很长的时间来运行。一般来说,一个执行输入输出操作的函数不应该被认为是内联的,因为它需要很长的时间。

内联display() 方法的作用很小,因为执行I/O 语句的时间大大超过了函数调用的开销。

如果函数没有被内联调用,编译器可能会发出一个警告,这取决于你运行的编译器。JavaC# 编程语言不支持内联函数。

内联函数,最后但并非最不重要,是C++的一个关键组成部分。当内联函数被正确利用时,它们可以提高工作效率。但是,当内联函数被乱用时,它们就不能。

换句话说,不要指望软件能有所改善。确保你的几个函数是内联的。

内联函数的优点

  • 没有与函数调用相关的开销。
  • 使用内联函数可以避免函数的返回调用的开销。
  • 当函数被调用时,它不必在堆栈上推送和弹出变量,从而节省了时间。
  • 当我们利用内联函数时,编译器可以在函数体上应用特定环境的优化,而这些优化是普通函数调用所不具备的。

内联函数的缺点

  • 缓存缺失是由大型内联程序引起的,这降低了效率。
  • 在编译过程中,在代码中到处复制函数体的开销在小程序中是微不足道的,但在庞大的代码库中会产生重大影响。
  • 如果我们需要程序中某个函数的地址,编译器就无法内联它。因为编译器必须为一个函数分配存储空间,为其提供地址。内联函数不接受存储,而是存储在符号表中。
  • 由于内联函数扩大了二进制可执行文件的数量,它们可能会导致 thrashing。计算机的性能会因为内存中的颤动而受到影响,我们的代码效率也会因此而受到影响。
  • 如果有人试图更新内联函数里面的代码,所有的调用位置都必须重新编译。因为编译器将不得不更新所有的代码来识别新的内容。否则,它将继续像以前一样工作。
  • 额外的寄存器会被内联函数增加的变量所消耗。如果内联后使用寄存器的变量数量增加,寄存器变量资源利用的开销就会增加。这意味着,每当内联函数的主体在函数调用过程中被交换时,函数所使用的全部变量集也会被输入。因此,用于变量的寄存器的数量将被提高。因此,如果变量的数量由于函数内联而激增,寄存器的消耗无疑会受到影响。

总结

在这篇文章中,我们看了内联函数,它们是什么,何时使用它们,以及一些实际的演示。我们已经看到了内联函数是如何比预处理程序宏更有效的。

我希望这个教程能给你带来启发,并在你今后的程序中有所帮助。