您的位置:首页 > 编程语言 > C语言/C++

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

2011-11-25 18:42 417 查看
浅谈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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: