const
const
位于*
的左侧: 用来润饰指针所指向的变量,指针指向常量。
// 指针不容许扭转数据int b = 500;const int *a = &b;*a = 600; // error
// 能够通过变量自身去批改int b = 500;const int *a = &b;b = 600;cout << *a << endl; // 600
const
位于*
的右侧: 用来润饰指针自身,指针是常量。
// 指针自身是常量,定义时须要初始化int b = 500;//int * const a; // errorint * const c = &b; // error*c = 600; // 失常,容许改值cout << *c << endl;
const
用在成员函数中, 位于function_name () const {}
咱们在定义类的成员函数中,经常有一些成员函数不扭转类的数据成员。 也就是说这些函数的 readonly function
,而有一些函数要批改类的数据成员的值。 如果在readonly function
都加上const
进行标识,无疑会进步程序的可读性。 其实还能进步程序的可靠性,已定义成const
的成员函数,一旦希图扭转数据成员的值,则编译器按错误处理。
class A{public: A(int x) : a(x) {} int get() const { return a; } int get2() const { return a++; } // ERROR read-only objectprivate: int a;};int main(int argc, char const *argv[]){ A obj(10); cout << obj.get() << endl; cout << obj.get2() << endl; return 0;}
const 润饰之后,readonly function
也将只能调用 readonly function
, 其实很好了解,如果readonly function
函数调用了其余函数,可能数据就会发生变化。
class A{public: A(int x) : a(x) {} int get() const { get2(); return a; } // 谬误,不能调用非 readonly function int get2() const {}private: int a;};int main(int argc, char const *argv[]){ A obj(10); int b = obj.get(); cout << b << endl; return 0;}
如果类的数据成员加上mutable
后,润饰为 const
的成员变量,也能够批改。
class A{public: A(int x) : a(x) {} int get() const { return ++a; }private: mutable int a;};int main(int argc, char const *argv[]){ A obj(10); int b = obj.get(); cout << b << endl; return 0;}
- const 位于函数申明前,意味着函数的返回值是常量
面试时须要留神的是: 面试时应该形容const的只读
,而不仅仅是常量,关键字const的作用是为读你代码的人传播十分有用的信息。 实际上,申明一个参数为常量是为了通知用户这个参数的利用目标。 如果你曾花很多工夫清理其他人留下的垃圾,你就会很快学会感激这点儿多余的信息。 当然,懂得用 const 的程序员很少会留下垃圾让他人来清理。 通过给优化器一些附加的信息, 应用关键字const兴许能产生更紧凑的代码。
正当地应用关键字const能够使编译器很天然地爱护那些不心愿被扭转的参数, 避免其被无心的代码批改。 简而言之,这样能够缩小bug的呈现。
volatile
volatile 关键字是一种类型修饰符,用它申明的类型变量示意能够被某些编译器未知的因素更改,比方:操作系统、硬件或者其它线程等。
遇到这个关键字申明的变量,编译器对拜访该变量的代码就不再进行优化。
volatile限定修饰符的用法与const十分类似都是作为类型的附加修饰符。例如:
volatile int display_register;volatile Task *curr_task;volatile int ixa[ max_size ];volatile Screen bitmap_buf;
display_register是一个int型的volatile对象;
curr_task是一个指向volatile的Task类对象的指针;
ixa是一个volatile的整型数组,数组的每个元素都被认为是volatile的;
bitmap_buf 是一个volatile的Screen类对象,它的每个数据成员都被视为volatile的。
volatile的语法与const是一样的,然而volatie的意思是“在编译器意识的范畴外,这个数据能够被扭转”。不知什么起因,环境正在扭转数据(可能通过多任务处理),所以,volatile通知编译器不要擅自做出无关数据的任何假设,在优化期间这是特地重要的。如果编译器说:我曾经把数据读进寄存器,而且再没有与寄存器接触。”在个别状况下,它不须要再读这个数据。然而,如果数据是volatile润饰的,编译器则不能做出这样的假设,因为数据可能被其余过程扭转了,编译器必须重读这个数据而不是优化这个代码。
就像建设const对象一样,程序员也能够建设volatile对象,甚至还能够建设const volatile 对象。 这个对象不能被程序员扭转,但可通过里面的工具扭转。
例1: 关键字volatile有什么含意?并给出3个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地扭转,这样,编译器就不会去假如这个变量的值了。准确地说就是,优化器在用到这个变量时必须每次都小心地从新读取这个变量的值,而不是应用保留在寄存器里的备份。
上面是volatile变量的几个例子:
- 并行设施的硬件寄存器(如状态寄存器)
- 一个中断服务子程序中会拜访到的非主动变量(Non-automatic varbliaes)。
- 多线程利用中被几个工作共享的变量。
例2: 一个参数能够既是const又是volatile吗?一个指针能够是volatile吗?解释为什么。
第一个问题:能够。一个例子就是只读的状态寄存器。它是volatile,因为它可能被意想不到地扭转;它又是const, 因为程序不应该试图去批改
第二个问题: 能够。 只管这并不很常见。一个例子是当一个中断服务子程序批改一个指向一个buffer的指针时。
例3: 上面的函数有什么谬误?
int square(volatile int *ptr) { return *ptr * *ptr;}
这段代码的目标是用来返还指针*ptr
指向值的平方,然而,因为*ptr
指向一个volatlie型参数,编译器将产生相似上面的代码:
int square(volatile int *ptr) { int a, b; a = *ptr; b = *ptr; return a * b;}
因为*ptr
的值可能被意想不到地扭转,因而a和b可能是不同的。 后果,这段代码可能无奈返回你所冀望的平方值。
正确的代码如下:
int square(volatile int *ptr) { int a = *ptr; return a * a;}
static
- 函数体内static变量的作用范畴为该函数体,不同于auto变量,该变量的内存只被调配一次,因而其值在下次调用时仍维持上次的值。
- 在模块内的static全局变量能够被模块内所有函数拜访,但不能被模块外其余函数拜访。
- 在模块内的static函数只可被这模块内的其余函数调用,这个函数的应用范畴被限度在申明它的模块内。
- 在类中的static成员变量属于整个类所领有,对类的所有对象只有一份复制
- 在类中的static成员函数属于整个类所领有,这个函数不接管this指针,因此只能拜访类的static成员变量。