没有学不会的 C++:const 关键字

constC++ 中的关键字,它会在编译期间(时机很重要),告诉编译器这个对象是不能被修改的。初学者一般会认为 const 是个麻烦的东西,因为它常常让你的程序编译不通过,而去掉了 const 之后,就不会有这么多「问题」了,实不相瞒,其实我刚学 C++ 的时候,有一段时间就处于这种状态。

但实际上,const 非常有用:

  1. 他可以保护变量,防止它们被无意的修改。
  2. 它可以传达有效的信息给读你代码的人:这个变量是不能被修改的,或者这个函数不会修该对象的成员,等。
  3. const 关键字可以优化编译结果,让可执行程序更为紧凑。
  4. const 修饰的变量还可以写入 ROM 介质。

总之,我认为合理的使用 const 可以让你写出来的程序更为严谨、健壮,不易出错,乃至于更加高效。

const 与变量

const 修饰常量,比较容易混淆的是:「 const 类型的常量指针」和「指针所指向的内容为 const 」之间的区别:

int i = 0;
const int* p1 = &i; 
int const* p2 = &i; 

上面代码表示指针所指的内容为 const,你不能做 *p1 = 1; 这样的操作,但可以 p1++;

int* const p3 = &i; 
const int* const p4 = &i; 

以上代码中,p3const 指针,你无法修改 p3,如 p3++;,但你可以执行 *p3 = 1;。最后一行中,p4 和其所指向的内容都是 const 的。这里的规律是:如果 const* 号左边,就表示指针所指的内容是常量,否则指针本身是常量。

另外,我们要尽可能的减少对 const 常量的强制转换操作,即将 const 变量强制转换为非 const 的,或相反,尤其是前者,因为这会破坏你对常量赋予的承诺,可能会导致误操作,从而引入隐蔽 bug

const int i = 9;
// 强制将常量 i 转换为普通变量
const_cast<int&>(i) = 6;  
int j;
// 编译失败; 因为该语句强制将变量 j 转换成了常量
static_cast<const int&>(j) = 7; 

const 与函数

const 与函数结合,我们需要考虑3种情况:

  1. const 常量作为函数的参数传入
  2. 函数返回 const 类型
  3. 声明类的成员函数为 const

const 常量作为参数传入时,该常量一定需要是引用类型,否则 const 起不到应有的作用,例如

class Dog {
    string name_;
public:
    Dog(const string& name) { name_ = name; }
    void setName(const string name);
    void setName(string name);
};

上面两个 setName() 函数等价,因为它们都是值传递(pass-by-copy),进入函数的参数是一个临时副本,既然是一个副本,修改它或不修改它对外部没有任何影响,所以这样的声明没有意义。要使上面的 const 产生意义,应该改为传引用(pass-by-reference)的方式

    void setName(const string& name);
...
    Dog dog("");
    string strname = "xiao-D";
    dog.setName(strname)

此时,外部调用 setName 就不用担心该函数会修改实参 strname 了。除此之外, setName 还可以被重载(overload)

    void setName(string& name); // 这里也只能是引用传递
    void setName(const string& name);

调用规则为,当你的实参为 const 类型时,会调用 void setName(const string& name); 函数,否则调用 void setName(string& name);

和函数的参数为 const 一样,当函数返回 const 类型时,也需要是引用类型,否则没有意义,即

    const string& getName() { return name_; }

这样可以防止外部对 object 的内部成员进行修改。

最后,我们来看一下 const 类型的函数,将以下函数加到 Dog 类中:

    void bark() const { cout << "dog " << name_ << " bark."; }

const 类型的函数表明该函数不会修改对象的成员,同时该函数也不可以调用非 const 函数,例如如下操作都是不允许的

    void bark() const {
        name_ = "da-D"; // can't modify any member
        setName("mark"); // can't call a non-const function
    }

除此之外,const 类型的函数也是可以重载的,即

    void bark() const { cout << "const dog " << name_ << " bark." << endl; }
    void bark() { cout << "non-const dog " << name_ << " bark." << endl; }

调用规则是,当对象是 const 类型时,调用 const 类型的函数,否则调用非 const 类型的函数。

Dog d1;
d1.bark("QQ");
const Dog d2;
d2.bark("Wechat");

得到的结果为:

non-const dog QQ bark.
const dog Wechat bark.

参考:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,292评论 8 265
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 晚风轻温扶烈酒,意卷深秋味证道,弄堂设晏方知客,饭露余香浴驱寒,浅弹轻唱伴烛眠,禅心初始梦还续,如醉今宵恋冬来
    深深是蓝阅读 207评论 2 7
  • 在iOS 11上运行Scrollview向下偏移64px或者20px,因为iOS 11废弃了automatical...
    c608阅读 4,227评论 0 2
  • 幼年时,读贺知章的《回乡偶书》“ 少小离家老大回,乡音无改鬓毛衰。儿童相见不相识,笑问客从何处来。”时,极为不解。...
    九昸阅读 206评论 0 2