现在的位置: 首页 > 综合 > 正文

浅谈C++中的几个关键字 : static, const, inline

2018年02月07日 ⁄ 综合 ⁄ 共 6406字 ⁄ 字号 评论关闭

 

                                               浅谈C++中的几个关键字 : static, const, inline

// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

static

static
是C++中很常用的存储类说明符,它被用来控制变量、函数的存储方式同链接方式。

下面我将从static 存储类说明符的产生原因、作用谈起,全面分析static 说明符的实质。

static 说明符的两大作用:

一、控制存储方式

        static 说明符被引入,以告知编译器将变量存储在程序的静态存储区,而非栈上空间。

       1、引出原因:

                     函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,而当程序执行到其作用域外时会释放掉。

                    这就产生了一个问题:如果想将函数中此变量的值保存至下一次调用,该如何实现?

                    最容易想到的方法是定义一个全局变量,但定义一个全局变量有着许多缺点,最明显的就是扩大了此变量的作用域,使得此变量

                    可经由其他函数或语句改写。

         2、解决方案:

                    因此在C++ 中引入了static 说明符,用它来修饰变量,它能够指示编译器为此变量在程序的静态存储区分配空间保存,这样既实现

                    了目的,也没有没有改变其原有的作用域。

二、控制链接方式

        对于所有不在函数内或语句块内声明的对象,默认有外部链接。即在多个文件中可声明多次,但只指向同一个对象

        如果在声明对象时引入 static, 则所声明的变量或函数只在当前文件内可见,使得外部链接变为内部链接。

static作用分析总结:

       static 说明符总是使得变量或对象的存储形式变成静态存储,对于全局变量是内部链接,对于局部变量是无链接。

       对于局部变量,改变了其存储方式;对于全局变量,改变了其链接方式。

 

类中的static 成员:

一、出现原因及作用:

        1、需要一个数据成员由类的各个对象共享,为整个类而非某个对象服务。

        2、力求不破坏类的封装性,要求此成员隐藏在类的内部,对外不可见。

         类的static 成员满足了上述要求,因为它具有如下特征:有独立的存储区,属于整个类。

二、注意:

         1、对于静态数据成员,链接器会保证它拥有一个单一的外部定义。静态数据成员按定义出现的先后顺序依次初始化,

               注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

          2、类的静态成员函数是属于整个类而非类的对象,所以它没有this 指针,这就导致了它公能访问类的静态数据和静态成员函数。

// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

const

const 是C++ 中常用的类型限定符,但我在工作中却发现,许多人使用它仅仅是想当然,这样有时也会用对,但在某些微妙的场合,可就没有那么幸运了。

究其实质原由,大多因为没有搞清const 类型限定符的本质。这里我将对const 类型限定符进行一个分析,溯其本源究其本质,希望对大家理解const 有所帮助。

C++中为什么要引入 const

        C++ 的作者当初是出于怎样的目的引入(或称保留) const 关键字的呢?   这是一个有趣又有益的话题,对理解 const 很有帮助。

1。大家知道,C++ 有一个类型严格的编译系统,这使得C++ 程序的错误在编译阶段即可发现许多,从而使出错率大为减少,

       也因此 成为了C++ 与 C 相比有些突出优点的一个方面。

2。C 中很常见的预处理指令 #define  VariableName    VariableValue  可以很方便地进行值替换,这种替换在至少在以下三个方面

       优点表现突出:

  •  一是避免了意义模糊的数字出现,使得程序语义清晰流畅, 如下例: #define    USER_NUM_MAX     108    。这样就避免了直接使用数字108带来的困惑。
  •  二是可以很方便地进行参数的调整与修改。如上例,当人数由108变为200时,在此改动一处就可。          
  •  三是提高了程序的执行效率。由于使用了预编译器进行值替换,并不需要为这些常量分配存储空间,所以执行效率较高。

        鉴于以上的优点,这种预定义指令的使用在程序中随处可见。

3。说到这里,大家可能会迷惑上述所讲的1、2两点同 const 说明符有什么关系。好,请接着下看:

       预处理语句虽然有些以上所述的许多优点,但它也有个比较致命的缺点。即,预处理语句仅仅只是简单的值替换,缺少类型的检测机制。

       这样的预处理语句就可能享受 C++ 严格类型检查的好处,从而可能成为引发一系列错误的隐患。

4。好了,第一阶段结论好了:

       结论:   const 说明符推出的初始目的,就是为了取代预编译指令 #define ,在继承其优点的同时消除它的缺点。

       现在的它形式变成了:

                                               const   Tpye  VariableName = VariableValue;

       为什么 const 可以很好地取代预定义语句呢?  请看

       1、首先,以const  说明符修饰的常量值具有不可变性。这是它可取代预定义语句的基础。

       2、第二,它也同样可以避免意义模糊的数字出现,使得程序语义清晰的同时可以很方便地对参数进行调整与修改。

       3、第三,C++ 编译器一般不为普通 const 常量分配存储空间,而是将们保存在符号表中,这使得它真正成为了一个编译期间常量。

                         由于 没有了存储与读内存的操作,这使得它的效率也很高。这是它取代预定义语句的重要基础。

       4、最后,const  定义也同一般普通的变量定义一样,它会由编译器对它进行类型的检测。消除了预定义语句的隐患。

 

const 说明符使用情况分类详析

1。const 说明符用于指针的两种情况分析:

       int   a ;

       const  int   *p ;               //  指针类型为 const   int *, 指针指向类型为 const int  。指针变量为非 const 类型,但指向的的变量为 const 类型

       int  *const  p = &a  ;      //  指针类型为int   *const , 指针指向   int  。指针变量为 const 类型,指向的变量为 非const 类型

 

        const 类型指针的转换问题:

       1.、从" const 指针类型 " 到 " 非const 指针类型 " 的转换:

               除了 const char * 指针类型 可转换为 char * 类型外(这是为了对c语言的向下兼容)  ,

              任何的 const  type1 * 都不可转换为 type2 * 类型。

       2、从 " 非const 指针类型 " 到 " const 指针类型 " 的转换:

              这样的转换都是可以执行的。

 

2。const 说明符限定函数的传递值参数:

       void  Fun( const  int  Var);

       分析:

                 上述写法限定了参数Var不可在函数体内改变。而由值传递的特点可知,就算Var在函数体中改变了也不会影响到函数外部。

                 所以,此限定与函数的使用者无关,仅与函数的编写者有关。

      结论:最好在函数的内部进行限定,对外部调用者屏蔽以免引起困惑。如可改写如下:

                  void Fun( int Var)

                  {

                        const int &VarAlias = Var;

                        .....

                  }

3。const  限定函数的返回值类型

       const    int     Fun1();

       const    MyClass    Fun2();

       const    int    &Fun3();               

       cosnt    int    *Fun4();

       const    MyClass   &Fun5();    

       const   MyClass    *Fun6();

 

       分析:

                  上述写法仅限定函数的返回值不可被改写。

                  1.当函数返回为内置类型的数据时,那已经是一个数值,那是必定不可改写的,这时的const 可要可不要。但建议去掉。

                  2.当函数返回为自定义类型的对象,这时的对象仍然可能包含可被赋值的数据成员,所以此时有意义。

                  3.如返回的是一个引用或是指针时,这种情况最为常见,由地址变量的特点可知,适当使用const ,意义昭然。

4。const  限定类的成员函数

class ClassName

{
public:
     int Fun() const;

      .....
}

注意:

          采用这种const 后置的形式是一种规定,也是为了不引起混淆。在这个函数的声明和定义中均要使用const,因为const已经成为类型信息的一部分。 
          获得能力:可以操作常量对象。
         失去能力:不能修改类的数据成员,不能在函数中调用其他不是const的函数。

// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

inline

在上面谈了const后,下面再来谈一下inline这个关键字。之所以把inline放在这个位置,是因为inline这个关键字的引入原因和const十分相似。

下面分为如下几个部分进行阐述。

C++中引入inline关键字的原因:


  inline 关键字用来定义一个类的内联函数,引入它是为了取代C语言中表达式形式的宏定义。

        表达式形式的宏定义一例:    #define   ExpressionName(Var1,Var2)          (Var1 + Var2) * (Var1 - Var2)

一、为什么要取代这种形式呢,且听老夫慢慢道来:

  1.首先我们谈一下在C中使用这种形式宏定义的原因。

              C语言是一门效率很高的语言,这种宏定义在形式和使用上就像一个函数,但它使用预处理器来实现,没有了参数压栈、代码生成等一系列的操作。

              这样一来它的效率很高,这是它在C中被使用的一个主要原因。
  2.这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处。

              另外它的返回值也不能被强制转换为可转换的合适的类型。这样,它的使用就存在着一系列的隐患和局限性。
     3.在C++ 中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,

              你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。
     4. inline 推出的目的,也正是为了取代这种表达式形式的宏定义。inline 很好地继承了它的优点同时也消除了化的缺点。

 

二、为什么inline能很好地取代表达式形式的预定义呢?

对应于上面的1-3点,阐述如下:

  1. inline 定义的类的内联函数,函数的代码被保存在符号表中,在使用时直接进行替换(像宏一样展开),没有了调用的开销,效率很高。
  2.很明显,类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。

               然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
  3. inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。

三、在何时使用inline函数:
  1.首先,你可以使用inline函数完全取代表达式形式的宏定义。

  2.另外要注意,内联函数一般只会用在函数内容非常简单的时候。这是因为,内联函数的代码会在任何调用它的地方展开,

              如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。内联函数最重要的使用地方是用于类的存取函数。

四、如何使用类的inline函数: 

        简单提一下inline 的使用吧:

       1.在类中定义内联函数:   

             隐含式定义内联函数      

            class ClassName

           {
                .... 

                // 如果在类中直接定义,可以不使用inline修饰。默认为内联
                int  GetWidth() {return m_lPicWidth;}; ....
                 .... 
           }

      2.在类中声明,在类外定义:
           class ClassName

           {
                    ....

                    // 如果在类中直接定义,可以不使用inline修饰 
                   int   GetWidth(); 

                   .... 
           }

         inline  int  GetWidth()
         { 
               return m_lPicWidth; 
         }

抱歉!评论已关闭.