C++编程规范 编程风格 学习 (1) -- 积极使用const

来源:互联网 发布:手机淘宝触屏版登陆 编辑:程序博客网 时间:2024/05/21 22:26

积极使用 const

“const是我们的朋友:不变的值更易于理解、跟踪和分析,所以应该尽可能地使用常量代替变量,定义值的时候,应该把const作为默认的选项;常量很安全,在编译时会对其进行检查,而且它与C++的类型系统已浑然一体。不要强制转换const的类型,除非要调用常量不正确的函数。”

常量能够简化代码,因为只需查看定义处的代码就能知道它在各处的值了。
void fun(vector<int>& v){    //....    const size_t len = v.size();    //....}

一看len的定义就知道它在整个作用域的语义,通常只是把它理解为一个不可变的值,但是为什么前面加了const作为修饰?这里肯定有它的含义,如果只用size_t,那么len还有可能在后续的代码中被直接或者间接通过别名的方式修改,但是给它加了const它就不能被修改了,放在这里可以记录此时此刻v的size。编译器也会帮你检查到这一点。这有助于理解它的含义。

const并不深,例如假设类C有一个X* 类型的成员p。
class C{    public:        C();    ~C();    X* p;};
const C c;
c.p 是const的,但是p所指的对象不是。

“理解程序状态变化的方式和位置是非常重要的,const将此直接记录在了代码中,编译器可以帮助我们实施这一点。正确编写const有助于更好地理解设计,使代码更牢固、更安全。如果发现有哪个成员函数不可能是const的,通常会使我们更好地理解成员函数修改对象的方式。还可以理解哪些数据成员在物理常量性和逻辑常量性之间架起了桥梁。”

例如,当函数中有个只读的指针或引用时,就应该把它声明为const,

void* memcpy(void* dest, const void* src, size_t n);

指向原始数据src的指针被声明为指向常量的指针,这意味着这个函数不想改变指针所指的对象的内容,为了防止在函数体重无意的赋值,而且还允许把指针作为实参传递给常量。如果在第二个形参中也就是src没有限定为const,那么他在下面的语句中就不能传递t.

char* s = "SSSSS";const char* t = "TTTTTT";memcpy(s,t,5);
编译器需要保证memcpy不改变t所指向的内容。在原型中用const,指向常量和非常量的指针都能传递给t。
以上不仅能用于指针也能用于引用,在C++中按值传递对象的习惯用法是传递常引用:
void f( const string& s ){    s+= “test”;    //error, s为const类型,不能修改}void g(string& s){    s += "test";    //OK,s不是const}void g(string& s){    f(s);               //OK,s没被修改    s += "test";   //OK,被修改}void f(const string& s){    g(s);    //error,const string& 不能传给string&}

这样保证了test不能改变f
可以通过把const放在星号的后面来声明一个本身不可改变的指针:
char *const p;*p = 'a';//OK, 只有指针是常量,所指的内容可以修改++p;//ERR, 指针不允许被改变,不允许更改p所在的地址
为了禁止改变指针及其所引用的内容,在两个位置都加上const:
const char* const p;*p = 'a';//ERR, 错误,这是由于第一个const来约束的,及常量指针p所指的对象也是const类型,均不能修改++p;//ERR, 错误,这是由第二个const来做约束的,指针p是常量指针,它所在的地址不允许被改变。

关于指针和常量相关的东西在此记录一下,指针常量和常量指针很多人分不清,这也是由于翻译简化造成的,指针常量在英文里是“const pointer” 而常量指针是 pointer to const
指针常量是指针自身是常量、不可变,即地址不可变,它不能再指向其他地方了;
而常量指针是指向常量的指针,也就是指针所指的内容是常量不可变,而指针自身是可变的,还能指向其他地方。
const char* p2c;    //常量指针,指向常量的指针char* const cp = 0;     //指针常量char const *p2c_2;    //常量指针,指向常量的指针的另一种写法const char* const cp2c = 0;    //指向常量的常量指针char *p;    //普通指针size_t strlen( const char*);//.....int i = strlen( cp );    //ok, Note 1p2c = p;    //ok,Note 2p = p2c;    //error! Note 3

Note 1: 我们可以拷贝一个 “指向非常量的指针” 到 “指向常量的指针” ,比如说,虽然在标准库函数中strcmp、strlen这两个函数在声明时,接受指向const类型字符串的指针作为参数,但是给它门传一个指向非const类型的字符串指针也是被允许的。
Note 2: 一个指向常量的指针是可以引用非const字符串的数据,因为指针不是const它可以被赋值。
Note 3: 但是反过来就不行了,这种转换是不被允许的

const修饰的是与它右边最近的内容,如果紧接着的是*,那么就是指针指向的是常量,指针还能随便到处指,如果紧接着的是变量,那就说明这个变量再也不能被修改了。
例如 char const* p2c; 从最右边开始看,p2c一个变量,然后成了 *p2c 发现这伙是个指针,它指向某个东西,继续往右看,有了const,这就是这伙指向的东西是个const的,最后看到了char,就是这伙p2c这个指针所指的内存的数据类型是char型。连起来看,那就是p2c是个指针这伙指向的内存中存放的数据类型是常量型的char;
char* const cp; 从右往左读,cp一个变量,继续,发现有const修饰cp,这个变量是const类型不能被修改了,继续,发现 * ,这伙是指针啊,那就是这个指针是不可被修改了,最后看到char,连起来看,那就是这个cp是个指针,它指向的内存空间存放的数据是char类型,而自身又被加了const限定,cp他再也不可被修改了,他注定只能指向这一个地方。

char ** ppc;
const char **ppcc = ppc;    //error!

这么做是不行的,原因....(自己先记住吧)
const和指针先暂且到此。

当const和非const成员函数有这实质等价的实现时,令非const的版本去调用const版本可避免代码重复,而反过,即在const成员函数中调用非const的成员函数,就有有风险,这从逻辑上就打破了你当初设计这个const成员函数的意义,本来是不做任何改变的,现在却要强制改变,而且,在代码中还得用const_cast 把*this的const性质去掉,这么做是个不好的开始。








原创粉丝点击