内联成员函数编译
‘壹’ 内联函数
c++从c中继承的一个重要特征就是效率。假如c++的效率明显低于c的效率,那么就会有很大的一批程序员不去使用c++了。
在c中我们经常把一些短并且执行频繁的计算写成宏,而不是函数,这样做的理由是为了执行效率,宏可以避免函数调用的开销,这些都有预处理来完成。
但是在c++出现之后,使用预处理宏会出现两个问题:
为了保持预处理宏的效率又增加安全性,而且还能像一般成员函数那样可以在类里访问自如,c++引入了内联函数(inline function).
内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,可以进行参数,返回值类型的安全检查,又可以作为成员函数。
预处理器宏存在问题的关键是我们可能认为预处理器的行为和编译器的行为是一样的。当然也是由于宏函数调用和函数调用在外表看起来是一样的,因为也容易被混淆。但是其中也会有一些微妙的问题出现:
问题1
问题2:
问题3:
预定义宏函数没有作用域概念,无法作为一个类的成员函数,也就是说预定义宏没有办法表示类的范围。
在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真正的函数。内联函数具有普通函数的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用内联函数。
内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省去了函数调用时候的压栈,跳转,返回的开销。我们可以理解为内联函数是以 空间换时间 。
为了定义内联函数,通常必须在函数定义前面放一个inline关键字。但是在类内部定义内联函数时并不是必须的。任何在类内部定义的函数自动成为内联函数。
构造函数Person,成员函数PrintPerson在类的内部定义,自动成为内联函数,当然也并不是所有的函数都是内联函数,因为编译器会根据函数的复杂度来决定是否要把函数当作内联函数。
内联函数并不是何时何地都有效,为了理解内联函数何时有效,应该要知道编译器碰到内联函数会怎么处理?
对于任何类型的函数,编译器会将函数类型(包括函数名字,参数类型,返回值类型)放入到符号表中。同样,当编译器看到内联函数,并且对内联函数体进行分析没有发现错误时,也会将内联函数放入符号表。
当调用一个内联函数的时候,编译器首先确保传入参数类型是正确匹配的,或者如果类型不正完全匹配,但是可以将其转换为正确类型,并且返回值在目标表达式里匹配正确类型,或者可以转换为目标类型,内联函数就会直接替换函数调用,这就消除了函数调用的开销。假如内联函数是成员函数,对象this指针也会被放入合适位置。
类型检查和类型转换、包括在合适位置放入对象this指针这些都是预处理器不能完成的(不能通过宏来实现)。
但是c++内联编译会有一些限制,以下情况编译器可能考虑不会将函数进行内联编译:
内联仅仅只是给编译器一个建议,编译器不一定会接受这种建议,如果你没有将函数声明为内联函数,那么编译器也可能将此函数做内联编译。一个好的编译器将会内联小的、简单的函数。
‘贰’ C++内联函数在 在编译时是将该函数的目标代码插入每个调用该函数的地方
内联函数在调用时,是将调用表达式用内联函数体来替换,而一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中。
如果内联失败这个函数就是一个普通的函数,普通的函数不会被编译器展开,只是作为函数调用。内联函数比普通函数效率高的原因就是编译器在调用处把这个函数展开,展开就是直接执行代码而不是调用这个函数,像宏展开的意思。
(2)内联成员函数编译扩展阅读:
宏调用并不执行类型检查,甚至连正常参数也不检查,但是函数调用却要检查。c语言的宏使用的是文本替换,可能导致无法预料的后果,因为需要重新计算参数和操作顺序。在宏中的编译错误很难发现,因为它们引用的是扩展的代码,而不是程序员键入的。
许多结构体使用宏或者使用不同的语法来表达很难理解。内联函数使用与普通函数相同的语言,可以随意的内联和不内联。
‘叁’ 内联成员函数的优缺点【C++】
优点是提高运行时间效率,缺点是增加了空间开销
对于普通函数,函数调用需要时间和空间开销,调用函数实际上将程序执行流程转移到被调函数中,被调函数的代码执行完后,再返回到调用的地方。这种调用操作要求调用前保护好现场并记忆执行的地址,返回后恢复现场,并按原来保存的地址继续执行。对于较长的函数这种开销可以忽略不计,但对于一些函数体代码很短,又被频繁调用的函数,就不能忽视这种开销。引入内联函数正是为了解决这个问题,提高程序的运行效率。
对于内联函数,在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。由于在编译时将内联函数体中的代码替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间开销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。
‘肆’ 用C++编程,关于内联函数和成员函数的!谢谢啦~
#include<iostream>
usingnamespacestd;
classssmemset{
private:
inta[20];
public: //两个重载的构造函数,类内默认为内联函数。
ssmemset()
{
for(inti=0;i<20;i++)
a[i]=0;
}
ssmemset(ints1[])
{
for(inti=0;i<20;i++)
a[i]=s1[i];
}
voidprint();
};
inlinevoidssmemset::print() //外部定义的内联函数。
{
inti;
for(i=0;i<20;i++)
cout<<a[i]<<' ';
cout<<endl;
};
voidmain()
{
inta[20]={1,3,5,7};
ssmemsetA;
ssmemsetB(a);
A.print();
B.print();
}
memset是标准库的关键字不能用来声明类名。
‘伍’ 内联函数与普通函数比较,在声明、编译时有什么不同
在类声明的内部声明或定义的成员函数叫做内联(INLINE)函数.
引入内联函数的目的是为了解决程序中函数调用的效率问题。
在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。显然,这种做法不会产生转去转回的问题,但是由于在编译时将函数体中的代码被替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间代销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。
在程序中,调用其函数时,该函数在编译时被替代,而不是像一般函数那样是在运行时被调用。
函数调用也会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。引入内联函数实际上就是为了解决这一问题。
‘陆’ C++中内联函数是什么意思
内联函数具有一般函数的特性,它与一般函数所不同之处只在于函数调用的处理。一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。在使用内联函数时,应注意如下几点:
1.在内联函数内不允许用循环语句和开关语句。
如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
2.内联函数的定义必须出现在内联函数第一次被调用之前。
3.本栏目讲到的类结构中所有在类说明内部定义的函数是内联函数。
‘柒’ 什么叫内联成员函数,代码膨胀,刚学c++看什么书好~我有一点c语言基础
内联函数如果要精确定义可以到MSDN上查询
我只是大略跟你说明一下
你首先应该了解代码复用性
由于我们在实现某个程序,而某个程序中存在某个功能会频繁调用
我们就会把这个功能抽象成一个函数
每次调用普通函数,其实函数调用是一种软中断,每次调用的时候会进行现场保护
就是会保存如PSW的值 寄存器值
而函数返回之后就会恢复现场
这一些都需要CPU资源开销
而内联函数是一种与编译器的约定,本来编译器会根据你定义的函数
将每次调用该函数时都进行标记或是给一个地址值(实际上这个值是错误的,因为编译器无法知道其运行时的地址,链接器做的工作)
而如果函数标记了内联的话(inline),则编译器会先进行性能判断,如果OK则会将函数调用处的call指令到ret全部替换成你函数体的指令
也就是说 没有调用该函数,而是直接执行函数体内部的代码
而代码膨胀一说,因为本来函数调用就是为了代码复用
而你却直接把函数的本体全部添加到调用处了 就好比你没有写这个函数 而是重复函数内部的执行代码
如果你调用了100000次这样的内联函数
如果你每个函数内部都有10行的话
那么你可以想象编译器帮你复制粘贴了多少的代码。。
自己的理解,不懂HI我
‘捌’ 内联函数和成员函数的区别是什么
内联函数是指在调用衣柜函数时,不把他当作调用而处理,而是把这个函数的代码直接在调用他的函数里展开的形式,也可以理解为内联函数就相当于一段代码。不需要调用,效率就高些。成员函数是类中声明的函数,属于类。当然如果在类中定义的成员函数自动变为内联函数。
‘玖’ 类体外定义成员函数和 内联成员函数有什么区别
内联函数
在类声明内定义内联函数
内联函数
在C++中,用户可以创建实际上不调用的短函数,他们的代码在每次调用的程序行里得到扩展。这个过程类似于使用类似函数的宏。为使一个函数在程序行进行代码扩展而不被调用,只要在函数前面加上关键字inline即可。
例如,在下面的程序,函数max()在行内扩展而不被调用:
#include<iostream>
usingnamespacestd;
inlineintmax(inta,intb)
{
returna>b?a:b;
}
intmain()
{
cout<<max(10,20);
cout<<""<<max(99,88);
}
上面的程序等价于下面的程序:
#include<iostream>
usingnamespacestd;
intmain()
{
cout<<(10>20?10:20);
cout<<""<<(99>88>99:88);
}
内联函数是C++的一个重要补充的原因是,他们能使程序员写出非常有效的代码。因为类一般要求几个经常被执行的接口函数,因此,这些函数的效率在C++中是非常重要的。我们知道,每次调用函数时,变元要进栈,各种寄存器内容要保存;函数返回时,又要恢复他们的内容。问题是这些指令要占用时间。但是,如果函数在行内扩展,上述那些操作就不存在了。当然,虽然函数行内扩展能产生较快的速度,但由于重复编码会产生较长的代码,因此最好只内联那些能明显影响程序性能的函数。
inline对编译器是一种请求,而不是命令。编译器可以选择忽略它。还有,一些编译器不能内联所有类型的函数。例如,通常编译器不能内联递归函数。必须查阅自己的编译器用户手册以了解对内联的限制。如果一个函数不能被内联,它就被当作一个正常的函数调用。
inline关键字不是C++的 C子集 的一部分,因此,C89没有定义它,然而,C99中增加了它。
内联函数可以是类的成员。
classmyclass{
inta,b;
public:
voidinit(inti,intj);
voidshou();
};
inlinevoidmyclass::init(inti,intj)
{
a=i;
b=j;
}
inlinevoidmyclass::show()
{
cout<<a<<""<<b<<" ";
}
在类声明内定义内联函数
在类声明内(大括号之内)定义内联函数是可能的。如果一个函数是在类声明内定义的,它将自动的转换成内联函数(如果可能的话)。没有必要(但不是错误)在函数声明的前面再加上关键字inline。
classmyclass{
inta,b;
public:
//automaticinline
voidinit(inti,intj){a=i;b=j;}
voidshow(){cout<<a<<""<<b<<" ";}
}
构造函数和析构函数也可以是内联的。
——————————————————————————————————————————
参考文献:
C++参考大全(第四版)