内联函数¶
内联函数(inline)快。
函数调用的开销¶
在函数中调用其他函数。
每一次函数调用 都有开销。电脑CPU都要做操作。
int foo(int x)
{
int result;
result = x*x;
return result;
}
函数调用开销:
- push 函数参数
- call 函数
- push ebp建立函数的栈帧
- mov ebp,esp
- sub esp, 20 分配局部变量内容
- 执行函数体的代码
- mov eax,返回值
- mov esp,ebp清除函数的栈帧
- pop ebp
- 执行返回指令
- add esp,dd 取消函数参数
准备操作 执行操作 收尾操作。
内联函数与宏函数¶
C++为了和C语言一样快,而做的措施。
内联函数是其中的一种。
在所有的语言中,C语言是最快的。
C语言有预处理器宏。预处理函数。使得C语言运行很快。
预处理宏 一般大写。 在C语言里也把它叫函数。
#define SQUARE(X) ((X)*(X))
要多加一些小括号。避免发生错误。
和普通函数不一样。
优点:在预处理阶段进行了文本替换。而不是再写一个函数,避免函数调用的开销,所以就快。
缺点:因为是普通文本替换,容易出错。
所以C++提供更好的方法:内联函数。
内联函数和预处理宏函数速度一样。
在函数前面加inline 那就是内联函数。其他的都不用变。
C++编译的时候,检查保证没有错误,然后进行替换。也不是函数调用,没有调用的开销。
C预处理宏 没有办法进行检查,因为是在预处理阶段。
C++inline函数取代C语言的宏函数。
C++ inline更安全。
内联函数不一定内联¶
- 函数过大
- 函数递归
- 语法不对
- 编译器没有启用内联,或没有内联功能
内联函数不能写成像普通函数那样 一个声明 一个定义。
内联函数只能有一个,写在最前面。
内联函数不需要源文件,只写在头文件里。不能分成两部分。和普通函数不一样。
类内部的内联函数¶
C++的功能
宏函数不可能写在类里,类的成员函数没有宏函数这样的。
类中只能写inline 内联函数。
根据需要写内联函数
比较小的函数写成内联函数,例如简单的构造函数,比较大的写了也没有用 函数里面代码很多的时候,可以写 但是写了C++编译器也不做内联。
class Point
{
int i,j,k;
public:
Point() : i(0),j(0),k(0){}
Point(int ii, int jj, int kk) : i(ii),j(jj),k(kk){}
void print(const string& msg) const
{
if (msg.size() != 0) cout << msg << endl;
cout << "i = " << i << ", "
<< "j = " << j << ", "
<< "k = " << k << endl;
}
};
在类里面定义的就是内联函数,前面不需要加inline。
一个类普通情况下:
头文件写声明,源文件写定义。
内联函数要写在头文件中。或者直接写到类的内部。
#include <stdio.h>
#include <iostream>
class Point
{
int i,j,k;
public:
Point() : i(0),j(0),k(0){}
Point(int ii, int jj, int kk) : i(ii),j(jj),k(kk){}
void print(const std::string& msg) const;
};
inline void Point::print(const std::string& msg) const
{
if (msg.size() != 0) std::cout << msg << std::endl;
std::cout << "i = " << i << ", "
<< "j = " << j << ", "
<< "k = " << k << std::endl;
}
带内联函数的Stash和Stack¶
Stash和Stack成员函数做成内联函数,加快速度,小的函数。
在头文件中,可以使用inline单独写函数实现。也可以在类里面直接写,不需要inline修饰。
构造函数中可以使用初始化列表,更加方便。因为本身就是初始化的。
Stack中的方法都是小方法,所以可以都写成内联函数,都在.h文件中。不需要源文件。
有了内联函数 Stash和Stack会更有效率。运行速度会更快。
- 把比较小的函数变成内联函数。
- 内联函数一定要放到头文件里
构造函数做成内联的。不能在.cpp中 应该在.h文件。
两种方法:
-
.h头文件中
-
.h头文件定义中 直接定义
初始化列表:
因为构造方法里面的代码都是初始化,所以可以使用初始化列表。
析构函数也做成内联函数。
// C++的Stash
class Stash
{
private:
int size;// 每一个是多大。存字符串的话就是最多的存多少字符。
int quantity;// 数量。一共可以保存多少个。
int next;// 已经保存了多少个。
unsigned char* storage;// 指针
public:
//构造函数。对成员进行初始化 使用初始化列表
//在类里面。现在就是内联的 不需要inline。
Stash(int sz, int initQuantity = 0) : size(sz),quantity(0),storage(0)
{
inflate(initQuantity);
}
int add(const void* element);
// 扩大内存
void inflate(int increase);
int count()
{
return next;
}
void* fetch(int index)
{
assert(0 <= index);
if (index >= next) {
return 0;
}
return &(storage[index * size]);
}
~Stash()//析构函数 做成内联的
{
if (storage != 0) {
delete [] storage;
}
}
};
在头文件中。比较小的函数做成内联的。¶
add和inflate函数比较大,就不做内联的。
count和fetch比较小,做成内联的。
inline int Stash::count()
{
return next;
}
inline void* Stash::fetch(int index)
{
assert(0 <= index);//要包含C++头文件#include <cassert>
if (index >= next) {
return 0;
}
return &(storage[index * size]);
}
内联函数一定要在.h文件里。
也可以写到类的内部。
内联函数编程指南¶
内联函数写法不统一,不同的人写的不一样,为了统一做的编程指南。
写成这样的比较好。
class Rectangle
{
int width, height;
public:
//构造函数
Rectangle(int w = 0, int h = 0);
int getWidth() const;
void setWidth(int w);
int getHeight() const;
void setHeight(int h);
};
inline Rectangle::Rectangle(int w, int h) : width(w), height(h) {}
inline int Rectangle::getWidth() const
{
return width;
}
inline void Rectangle::setWidth(int w)
{
width = w;
}
inline int Rectangle::getHeight() const
{
return height;
}
inline void Rectangle::setHeight(int h)
{
height = h;
}
运行代码 测试是否正确。
//测试
void test()
{
Rectangle r(19, 47);
int iHeight = r.getHeight();
cout << iHeight << endl;
r.setWidth(100);
r.setHeight(r.getWidth());
cout << r.getWidth() << endl
<< r.getHeight() << endl;
}
内联函数写在类的定义外面。
优点:
想要内联的时候就加上inline 不想的时候就把inline去掉。方便。
内联如果写在类的里面,不想做成内联了 还得从里面复制出来。麻烦。所以写在外面。