inline内联的用法与作用
内联函数是一种编译机制,优点从代码上是看不出来的,但是程序的执行效率上有差别,通常,编译器对函数调用的处理是一种类似中断的方式,即当执行到函数调用语句时,程序把当前所有的状态信息比如CPU所有寄存器(其中一个很重要的就是指令指针寄存器)的值保存起来,然后放心大胆地转去执行那个函数的代码,执行完后再返回原来的地方,恢复原先保存过的状态信息,于是也就可以接着原来被中断的指令继续往下执行。这样,就很容易实现代码的结构化,因为可以把一些独立的功能模块写成函数,函数内部的变量和外部的变量互不影响,而且函数执行完后就可以释放这个函数内部变量的所使用的内存空间(这就是为什么函数退出后,其内部变量不再有效),对内存的使用也是很经济的(否则,如果一个大的程序全部由一个函数组成,那么所有的变量都得自始至终地占用内存空间),当然,还有其他优点,比如可以实现递归,总之是好处多多。
可是,任何事情往往都有两方面,这样做虽然好处多多,但也是有代价的,那就是前面所说的,任何一次函数调用,程序都得进行保存和恢复状态信息的动作,用数据结构的术语说就是进栈和退栈,当然,还有内存分配的过程,如果函数的代码非常少,这种代价并不是可忽略的,比如说,你编写一个类,里面有个记录状态的成员变量:
按照面向对象的思想,函数的属性应尽量的私有化,但外部怎么获得这个属性值呢?一般的方法就是加一个共有函数,这就实现的面向对象思想中所谓“通过公用接口操作对象的私有属性”。于是就变成了:
可是,任何事情往往都有两方面,这样做虽然好处多多,但也是有代价的,那就是前面所说的,任何一次函数调用,程序都得进行保存和恢复状态信息的动作,用数据结构的术语说就是进栈和退栈,当然,还有内存分配的过程,如果函数的代码非常少,这种代价并不是可忽略的,比如说,你编写一个类,里面有个记录状态的成员变量:
- Class MyClass
- {
- private:
- int m_iState;
- }
- Class MyClass
- {
- public:
- int GetState();
- private:
- int m_iState;
- }
- int MyClass::GetState()
- {
- return m_iState;
- }
但对你来说,也很委屈,怎么办,把所有的属性都改成public?让外部内码直接访问?况且,那样也不解决所有问题,因为有时候即使不是为了面向对象,我们也需要把独立的功能模块做成函数,比如说产生随机数的函数。我想
int iRand=rand();
总比:
int iRand=((int)(MULTIPLIER * Seed + INCREMENT)>>16)&0x7fff;
看起来舒服吧?(我这里只是打个比方,VC的rand函数并不是内联函数)
而内联函数就是解决这个问题了,对于程序员,他还是把独立功能写成函数的形式,但只要声明为内联,编译器就不把它编译成一次函数调用,而只是类似于把函数的代码拷贝到被调用的地方,而且这完全是编译器私下里完成的,原来的访问权限等问题丝毫不受影响。 这不是两全齐美了吗:在保证代码的面向对象性和结构化不受损失的条件下,程序的效率也没有损失,比如上面那个类,就变成了:
- Class MyClass
- {
- public:
- inline int GetState();
- private:
- int m_iState;
- }
- int inline MyClass::GetState()
- {
- return m_iState;
- }
当然,内联函数还有另外一种写法,就是直接写在类中,此时,不必使用“inline”关键字。
- Class MyClass
- {
- public:
- int GetState(){ return m_iState; }
- private:
- int m_iState;
- }
在解决C + +中宏存取私有的类成员的问题过程中,所有和预处理器宏有关的问题也随着消失了。这是通过使宏被编译器控制来实现的。在 C + +中,宏的概念是作为内联函数来实现的,而内联函数无论在任何意义上都是真正的函数。唯一不同之处是内联函数在适当时像宏一样展开,所以函数调用的开销被取消。因此,应该永远不使用宏,只使用内联函数。
任何在类中定义的函数自动地成为内联函数,但也可以使用i n l i n e关键字放在类外定义的函数前面使之成为内联函数。但为了使之有效,必须使函数体和声明结合在一起,否则,编译器将它作为普通函数对待。因此
- inline int PlusOne(int x);
- inline int PlusOne(int x) { return ++x ;}
一般应该把内联定义放在头文件里。当编译器看到这个定义时,它把函数类型(函数名+ 返回值)和函数体放到符号表里。当使用函数时,编译器检查以确保调用是正确的且返回值被 正确使用,然后将函数调用替换为函数体,因而消除了开销。内联代码的确占用空间,但假如 函数较小,这实际上比为了一个普通函数调用而产生的代码(参数压栈和执行C A L L)占用的空间还少。在头文件里,内联函数默认为内部连接——即它是static, 并且只能在它被包含的编译单元看到。因而,只要它们不在相同的编译单元中声明,在内联函数和全局函数之间用同样的名字也不会在连接时产生冲突。
为了定义内联函数,通常必须在函数定义前面放一个i n l i n e关键字。但这在类内部定义内联函数时并不是必须的。任何在类内部定义的函数自动地为内联函数。如下例:
- #include <iostream.h>
- class point{
- private:
- int i,j,k;
- public:
- point() {i=j=k=0; }
- point(int I,int J,int K) {
- i=I;
- j=J
- k=K;
- }
- void print(const char* msg="") const{
- if(*msg) cout<<"msg"<<endl;
- cout<<"i="<<i<<endl;
- cout<<"j="<<j<<endl;
- cout<<"k="<<k<<endl;
- }
- };
- main(){
- point p,q(1,2,3);
- p.print("value of p");
- q.print("value of q");
- }
转自:点击打开链接