C++几个常考的关键字的用法

1#define 宏定义

       #define编译指令的工作方式与文本编辑器或字处理器的全局搜索和替换命令相似。它实际上是在进入编译器的预处理阶段,就把源码中相应定义替换成设定的值。从这里我们就可以发现一个潜在的问题,它实质上并没有经过编译器检验。

       在《Effective++》中的第一条就是这样写到的:尽量用constinline而不用#define。其实它实际就是说“尽量使用编译器而非预处理”。(为什么是constonline将在后面讲到)

       但是,既然#define存在,我们就需要了解如何正确的使用它。它的基本语法有两个要注意的地方,一是不能以分号结束,另一个就是括号的使用。例如:

       #defineSQR_ONE(x) (x * x)

       #defineSQR_TWO(x) ((x) * (x))

 

       intmain()

{

       inta,b,c = 3;

       a= SQR_ONE(c + 3);

       b= SQR_TWO(c + 3);

       cout<<”a= ”<<a<<” b =“<<b<<endl;   

}

 

此时,第一个宏定义SQR_ONE在定义时没加括号,则a产生的表达式是c + 3 * c +3,此时结果为a =15;而第二个才是(c + 3)*( c +3),得到想要的结果36

2const常量

关键字const叫做限定符,因为它限定了声明的含义。使用const的好处在于它允许指定一种语义上的约束——某种对象不能被修改,且这种约束由编译器来实施。通过const,我们可以通知编译器和其他程序员某个值要保持不变。

const关键字用法比较多,在类外面,它可以用于全局和命名空间常量,以及静态变量(某一文件或程序块范围内的局部对象);在类内部,它可以用于静态与非静态成员;也可以和指针搭配,形成const指针和指向const的指针。例如:

const intMONTHS =12;   //声明了一个整形常量MONTHS,且初始化为12

 

const char *p =“hello”;            //声明了一个指向字符常量的指针

char * constq =“hello”;            //声明了一个指向字符类型的指针常量

voidfun1(const char *param1); //声明了一个函数,参数为一个指向常量的指针

voidTime::fun2(const char * param2)const;              //声明fun2为常成员函数,不能修改对象//中的数据成员

注:const必须在声明时完成初始化。在C中和C++的用法在开始时有点差异,在C中比C++限制更多,具体可参照可参考百度百科 CONST

比如:const int n =5;

      inta[n];         //ANSIC中将编译不通过,原因在它是只读变量,对于常量//使用#defineenum来定义

3static静态变量

C++static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。加了static关键字后,则该对象存在在内存的静态存储区内(具体的c++内存存储方式将在后面单独总结)。

1)面向过程中的static

在面向过程的static用法中,主要有以下几种:静态全局变量、静态局部变量以及静态函数。

静态变量不管是全局还是局部的,它的生命周期在整个程序运行中一直存在。还有一个需要注意的地方就是未经初始化的静态变量会自动初始化为0,而自动变量的值则不然。

l        静态全局变量

对于全局变量,加上static后,该变量就被定义成为一个静态全局变量。它实现了在整个文件中共享的功能,但是static不能被其他文件所用,其他文件可以定义相同名称的变量,不会起冲突(这与extern外部变量不同)。

l        静态局部变量

在局部变量前加上static后就是静态局部变量。对于静态局部变量我们需要注意就是它的作用域。首先它是静态的,这意味着它的生命周期是和整个程序相同的。其次由于它是局部的,所以其作用域也是局部的,比如属于某个方法,所以其作用域只能在这个方法里。还有就是对于静态局部变量它是程序运行到该对象处时才初始化,如果未指定初始化的值,则自动初始化未0,一旦初始化后,再次调用不再初始化,但可对其运算。

l        静态函数

对于静态函数,需要注意的是静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其他文件使用。

2)面向对象中的static(类中的static

在面向对象中的用法和上方类似,有静态数据成员和静态成员函数两种。

l        静态数据成员

对于静态数据成员,是指在类内部加static声明的成员。但需要注意的主要有以下两点:首先对于静态数据成员,它是属于类的,而不是属于某个对象实例,所以所有属于该类的对象恭喜该数据成员。其次是它依然存在这局部性这一特点。

l        静态成员函数

对于类的静态函数,比面向过程中的静态函数有一个不同的要求,就是静态成员函数里不能访问非静态成员。


 4inline内联函数

       内联函数是C++为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不再于编写方式,而在于C++编译器如何将它们组合到程序中。

内联函数的编译代码与其他程序代码内联起来,即编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,然后再跳回来。因此,内联函数的运行速度比常规函数稍快。但代价是需要占用更多内存。

要使用这项特性,必须采取下述措施:

l        在函数声明前加上关键字inline

l        在函数定义前加上关键字inline

内联函数和常规函数一样,也是按值来传递参数的。

5mutable关键字

  关键字mutable是C++中一个不常用的关键字,他只能用于类的非静态和非常量数据成员我们知道一个对象的状态由该对象的非静态数据成员决定,所以随着数据成员的改变,对像的状态也会随之发生变化!

如果一个类的成员函数被声明为const类型,表示该函数不会改变对象的状态,也就是该函数不会修改类的非静态数据成员.但是有些时候需要在该类函数中对类的数据成员进行赋值.这个时候就需要用到mutable关键字了

例如:

C++几个常考的关键字的用法
 1C++几个常考的关键字的用法class Demo
 2C++几个常考的关键字的用法{
 3C++几个常考的关键字的用法public:
 4C++几个常考的关键字的用法    Demo(){}
 5C++几个常考的关键字的用法    ~Demo(){}
 6C++几个常考的关键字的用法public:
 7C++几个常考的关键字的用法    bool getFlag() const
 8C++几个常考的关键字的用法    {
 9C++几个常考的关键字的用法        m_nAccess++;
10C++几个常考的关键字的用法        return m_bFlag;
11C++几个常考的关键字的用法    }
12C++几个常考的关键字的用法private:
13C++几个常考的关键字的用法    int  m_nAccess;
14C++几个常考的关键字的用法    bool m_bFlag;
15C++几个常考的关键字的用法};
16C++几个常考的关键字的用法
17C++几个常考的关键字的用法int main()
18C++几个常考的关键字的用法{
19C++几个常考的关键字的用法    return 0;
20C++几个常考的关键字的用法}
21C++几个常考的关键字的用法

编译上面的代码会出现 error C2166: l-valuespecifies constobject的错误说明在const类型的函数中改变了类的非静态数据成员.这个时候需要使用mutable来修饰一下要在const成员函数中改变的非静态数据成员

m_nAccess,代码如下:

C++几个常考的关键字的用法
 1C++几个常考的关键字的用法class Demo
 2C++几个常考的关键字的用法{
 3C++几个常考的关键字的用法public:
 4C++几个常考的关键字的用法    Demo(){}
 5C++几个常考的关键字的用法    ~Demo(){}
 6C++几个常考的关键字的用法public:
 7C++几个常考的关键字的用法    bool getFlag() const
 8C++几个常考的关键字的用法    {
 9C++几个常考的关键字的用法        m_nAccess++;
10C++几个常考的关键字的用法        return m_bFlag;
11C++几个常考的关键字的用法    }
12C++几个常考的关键字的用法private:
13C++几个常考的关键字的用法    mutable int  m_nAccess;
14C++几个常考的关键字的用法    bool m_bFlag;
15C++几个常考的关键字的用法};
16C++几个常考的关键字的用法
17C++几个常考的关键字的用法int main()
18C++几个常考的关键字的用法{
19C++几个常考的关键字的用法    return 0;
20C++几个常考的关键字的用法}
21C++几个常考的关键字的用法

这样再重新编译的时候就不会出现错误了!

  6volatile
有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。 volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:   
  volatile  BOOL  bStop   FALSE;   
    
  
在一个线程中:   
  while(  !bStop    
   
   ...   
   
  bStop   FALSE;   
 return;     
    
  
在另外一个线程中,要终止上面的线程循环:   
  bStop   TRUE;   
  while(  bStop  );   //
等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。 
这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:   
 ...   
  int  nMyCounter   0;   
  for(;  nMyCounter<100;nMyCounter++)   
   
 ...   
   
 ...   
  
在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试及操作总是对此寄存器中的值进行),但是另外有又段代码执行了这样的操作:nMyCounter  -=   1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不是同步的 

                                                                                            
7 extern
2A 
c++中,还可用来指定使用另一语言进行链接,这时需要与特定的转换符一起使用。目前microsoftc/c++仅支持”c”转换标记,来支持c编译器链接。使用这种情况有两种形式:
     extern “c” 声明语句
     extern “c” { 声明语句块 }

2B extern  LPDIRECTDRAW4      lpdd;  声明lpdd,但是不分配内存,只说明他是你可以用的变量,在此程序之外其他的程序中已经声名了他。 其实他就是防止名字冲突  被其修饰的变量(外部变量)是静态分配空间的,即程序开始时分配,结束时释放
如果一个头文件被  #include   到一个以上的源文件   里,这个头文件中所有的定义就会出现在每一个有关的源码文件里。这会使它们里的符号被定义一次以上,从而出现连接错误。   
        
解决办法就是不要在头文件里定义变量。你只需要在头文件里声明它们然后在适当的源码文件(应该  #include   那个头文件的那个)里定义它们一次。extern告诉编译器其所声明的符号的存在,并不会使编译器分配贮存空间。当做一个声明而不是做定义的时候,在声明前放一个关键字“extern” 
extern
关键字的作用是声明变量和函数为外部链接,即该变量或函数名在其它文件中可见。用其声明的变量或函数应该在别的文件或同一文件的其它地方定义。 
例如语句:extern int a;
    
仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。
    通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数


8  register
  
register声明的变量称着寄存器变量,在可能的情况下会直接存放在机器的寄存器中;但对32位编译器不起作用,当globaloptimizations(全局优化)开的时候,它会做出选择是否放在自己的寄存器中;不过其它与register关键字有关的其它符号都对32位编译器有效。

9  auto
  
它是存储类型标识符,表明变量(自动)具有本地范围,块范围的变量声明(如for循环体内的变量声明)默认为auto存储类型。


10 explicit

修饰构造函数 防止隐式转化
是针对单参数的构造函数而言
多于2个以上不会隐式转化,记住就是对构造函数很有用!explicit关键字用于取消构造函数的隐式转换,对有多个参数的构造函数使用explicit是个语法错误。

class A{
int a;
public:
explicit A(int i):a(i){}     
};

int main()
{
a(1),b(2);
b;
2;   //错误,不能隐式转换
return 0;
}


二、笔试面试常考问题

1const#define相比有什么不同?

       对于C++语言来说,两者都可以定义常量。但是前者比后者有更多的优点:

       1const常量有数据类型,而宏定义没有数据类型。编译器可以对前者进行类型安全检查,而对后者只是进行字符替换,没有类型安全检查,并且在字符替换中可能产意料不到的错误(边际效应)。

       2)有些集成化的调试工具可以对const调试,但不能对宏常量进行调试。

       对于#define的这种缺点,除了上面的const外,还可以用inline。内联函数不仅具有实现宏函数的效率,还加上了类型检查和可预计的行为这些优点。比如:

#definemax(a,b) ((a) > (b) ? (a) : (b))

int a = 5, b= 0;

max(++a,b);           //此时a值增加了2

max(++a,b+10);        //此时a值增加了1

而换成inline,我们就可以避免这种不可预见的情况,甚至还可以使用C++里的另一个功能——模板函数。比如换成以下的方式:

              inlineint max(int a, int b) { return a > b ? a : b;}

         或者

template

inline constT& max(const T& a, const T& b)

{ return a> b ? a : b; }

2、关键字static的作用是什么?

CC++语言中,static主要有以下几个作用:

(1)    函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此值在下次调用时仍维持上次的值。

(2)    在模块内的static全局变量可以被模块内的所以函数访问,但不能被模块外的其他函数访问。

(3)    在模块内的static函数只可被这一模块内的其他函数调用,但这个函数的使用范围被限制在声明它的模块内。

(4)    在类中的static成员变量属于整个类所拥有,对类的所以对象只是有一份拷贝。

(5)    在类中的static成员变量属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

注:对于类中的static,我们还可以用enum来替代,例如:

enum:enum {Len =30};

static:static const int Len =30;

                          访问时都可直接用ClassName::Len

3、关键字volatile有什么含义?一般用在什么地方?

       一个定义为volatile的变量说明这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确的说就是,优化器在用到这个变量时必须每次都小心的重新读取这个变量的值,而不是使用保存在寄存器里的备份。

       volatile主要用在以下几个地方:

(1)    并行设备的硬件寄存器(如状态寄存器)。

(2)    一个中断服务子程序中会访问到的非自动变量。

(3)    多线程应用中被几个任务共享的变量。

对于volatile变量作为参数时,它还可以是const。因为它不希望程序去修改它。而对于指针,同样可以使用volatile,比如中断服务子程序修改一个指向buffer的指针时。

4、在C++程序中调用被C编译器编译后的函数,为什么要加extern”C”

       C++语言支持函数重载,C语言不支持。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x,inty)。该函数被C编译后在库中的名称为_foo,而C++编译器则会产生_foo_int_int之类的名称。

       C++提供了C连接交换指定符号extern”C”解决名字匹配问题。

       注:extern的用法:extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。另外,extern也可用来进行链接指定。我们需要注意它和static的区别。

 5C++其他存储关键字

       除了上面讲到的staticconstC++主要还有以下存储关键字:

l               auto:将变量声明为自动变量。

l        register:在声明中指示寄存器存储类型。

l        extern:表明引用声明,即声明引用在其他地方定义的变量。

l        mutable:可以用来指定即使结构或类变量为const,对某个成员也可以被修改。

l        volatile:表示即使程序代码没有对内存单元进行修改,其值也可能发生变化。该关键字可以改善编译器的优化能力。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值