直观上定义:
联函数的定义与普通函数基本相同,只是在函数定义前加上关键字 inline。
inline void print(char *s)
{
printf("%s", s);
}
为什么使用内联函数
- 内联函数最初的目的:代替部分 #define 宏定义;
- 使用内联函数替代普通函数的目的:提高程序的运行效率;
普通函数和内联函数区别:
1、普通函数调用时是生成调用指令(跳转),然后当代码执行到调用位置时跳转到函数所在的代码段执行。
2、内联函数就把函数编译好的二进制指令直接复制到函数的调用位置。
内联函数的优点
就是提高程序的运行速度(因为没有跳转,也不需要返回),但这样会导致可执行文件增大
(冗余),也就是牺牲空间来换取时间。
内联分为显示内联和隐式内联
显示内联:在函数前 inline(C语言C99标准也支持) 在类声明外部定义叫做显式内联函数
class display
{
int t;
public:
void output(void)
};
display object;
inline void display::output(void)
{
cout << "i is " << i <<"\n";
}
隐式内联:结构、类中内部直接定义的成员函数,则该类型函数会被优化成内联函数。
,如:
class display
{
int t;
public:
inline void output(void)
{cout<<"i is "<< i << "\n";}
};
宏函数与内联函数的区别(优缺点)?
宏函数在调用时会把函数体直接替换到调用位置,与内联函数一样也是使用空间来换取时间,
1.宏函数不是真正的函数,只是代码替换,不会有参数压栈、出栈以及返回值,也不会检查参数类型,
因此所有类型都能使用,但这样会有安全隐患。
2.内联函数是真正的函数,被调用时会进行传参,会进行压栈、出栈,可以有返回值,并会严格检查参
数类型,这样就不能通用,如果想被多种类型调用需要重载。
内联和static
多数情况下,inline 前面会加static关键字。why?
分开理解:static 意味着本地化,每个包含头文件的C文件均在本地产生一个独立的内联函数。当有多个C文件包含头文件时,不会因为函数名相同而报重定义错误。(代价就是 代码所占的空间会变大)
谨慎使用 static:如果只是想把函数定义写在头文件中,用 inline,不要用static。static 和 inline 不一样:
static 的函数是 internal linkage。不同编译单元可以有同名的static 函数,但该函数只对 对应的编译单元 可见。如果同一定义的 static 函数,被不同编译单元调用,每个编译单元有自己单独的一份拷贝,且此拷贝只对 对应的编译单元 可见。
inline 的函数是 external linkage,如果被不同编译单元调用,每个编译单元引用/链接的是同一函数,同一定义。
上面的不同直接导致:如果函数内有 static 变量,对inline 函数,此变量对不同编译单元是共享的(Meyer's Singleton);对于static 函数,此变量不是共享的。看后面的代码就明白区别了。
static inline 函数,跟 static 函数单独没有差别,所以没有意义,只会混淆视听。
内联适用的条件
由于内联会造成可执行文件变大,并增加内存开销,因此只有频繁调用的简单函数适合作为内联。
调用比较少的复杂函数,内联后并不显著提高性能,不足以抵消牺牲空间带来的损失,所以不适合内联。
带有递归特性和动态绑定特性的函数,无法实施内联,因此编译器会忽略声明部分的inline关键字。
而内联函数在调用时,是将调用表达式用内联函数体来替换。在使用内联函数时,应注意如下几点:
1.在内联函数内不允许用循环语句和开关语句。
如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
2.内联函数的定义必须出现在内联函数第一次被调用之前。
3.类结构中所有在类说明内部定义的函数是内联函数。
在类外定义成员函数
成员函数是在类体中定义的。也可以在类体中只写成员函数的声明,而在类的外面进行函数定义
class Student
{
public :
void display( ); //公用成员函数原型声明
private :
int num;
string name;
char sex;
//以上3行是私有数据成员
};
void Student::display( )//在类外定义display类函数
{
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
Student stud1,stud2; //定义两个类对象
注意:在类体中直接定义函数时,不需要在函数名前面加上类名,因为函数属于哪一个类是不言而喻的。
但成员函数在类外定义时,必须在函数名前面加上类名,予以限定(qualifed)," :: "是 作用域限定符(field qualifier) 或称 作用域运算符 ,用它声明函数是属于哪个类的。
如果在作用域运算符“::”的前面没有类名,或者函数名前面既无类名又无作用域运算符“::”,如
::display( ) 或 display( )
则表示display函数不属于任何类,这个函数不是成员函数,而是全局函数,即非成员函数的一般普通函数。
类函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前,否则编译时会出错。
虽然函数在类的外部定义,但在调用成员函数时会根据在类中声明的函数原型找到函数的定义(函数代码),从而执行该函数。
在类的内部对成员函数作声明,而在类体外定义成员函数,这是程序设计的一种良好习惯。如果一个函数,其函数体只有2-3行,一般可在声明类时在类体中定义。多于3行的函数,一般在类体内声明,在类外定义。
内置(inline )函数
在类体中定义的成员函数的规模一般都很小,而系统调用函数的过程所花费的时间开销相对是比较大的。调用一个函数的时间开销远远大于小规模函数体中全部语句的执行时间。为了减少时间开销,如果在类体中定义的成员函数中不包括循环等控制结构,C++系统会自动将它们作为内置(inline)函数来处理。
class Student
{
public :
void display( )
{
cout<<"num:"<<num<<endl;cout<<"name:"
<<name<<endl;cout<<"sex:"<<sex<<endl;
}
private :
int num;
string name;
char sex;
};
其中第3行
void display( )
也可以写成
inline void display( )
将display函数显式地声明为内置函数。
以上两种写法是等效的。对在类体内定义的函数,一般都省写inline。
应该注意的是,如果成员函数不在类体内定义,而在类体外定义,系统并不把它默认为内置(inline )函数,调用这些成员函数的过程和调用一般函数的过程是相同的。如果想将这些成员函数指定为内置函数,应当用inline作显式声明。 如:
class Student
{
public : inline void display( );//声明此成员函数为内置函数
private :
int num;
string name;
char sex;
};
inline void Student::display( ) // 在类外定义display函数为内置函数
{
cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"sex:"<<sex<<endl;
}
在前面曾提到过,在函数的声明或函数的定义两者之一作inline声明即可。值得注意的是,如果在类体外定义inline函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中),否则编译时无法进行置换(将函数代码的拷贝嵌入到函数调用点)。但是这样做,不利于类的接口与类的实现分离,不利于信息隐蔽。虽然程序的执行效率提高了,但从软件工程质量的角度来看,这样做并不是好的办法。只有在类外定义的成员函数规模很小而调用频率较高时,才将此成员函数指定为内置函数
总结:
类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function)。但也存在缺点,就是每一调用处均会展开,增加了重复的代码量。
可以理解为内联函数的关键词是: 替换
引入内联函数的目的是为了解决程序中函数调用的效率问题。