Effective C++ 条款03:尽可能使用const
场景一 用于修饰指针
char greeting[] = "Hello";
char* p = greeting; // non-const pointer, non-const data
const char* p = greeting; // non-const pointer, const data
char* const p = greeting; // const pointer, non-const data
const char* const = greeting; // const pointer, const data
const在*左边,表示被指物是常量,指针所指向的内容不能修改,但是可以修改指针,让指针指向其他对象。
const在*右边,表示指针自身是常量,指针不能修改,不能指向其他对象,但是当前指向的内容可以修改。
const在*的两侧,表示指针自身是常量,被指物也是常量,指针不能指向其他对象,当前指向的内容也不能改变。
场景二 用于对象前、后
void f1(const Widget* pw);
void f2(Widget const * pw);
两种表达式的效果是一样的,都在*的左边,说明被指物是常量。
场景三 用于对STL迭代器的修饰
std::vector<int> vec;
const std::vector<int>::iterator iter = vec.begin(); // iter的作用相当于 T* const
*iter = 10; // 没问题,改变iter所指物
iter++; // 错误,iter是const
std::vector<int>::const_iterator cIter = vec.begin(); // cIter的作用相当于 const T*
*cIter = 10; // 错误,*cIter是个const
++cIter; // 没问题,改变cIter
场景四 用于返回值
class Rational {...};
const Rational operator* (const Rational& lhs, const Rational& rhs);
Rational a, b, c;
...
(a * b) = c; // 显然在把返回结果设置为const以后,就不允许这样的操作发生
if (a * b = c) // 如果设置返回值为const的时候,这种手误的操作也不会发生
场景五 用于成员函数本体
const成员函数
class TextBlock {
public:
'''
const char& operator[](std::size_t position) const // operator[] for const对象
{return text[position];}
char& operator[](std::size_t position)
{return text[position];]}
private:
std::string text;
}
// 调用一
TextBlock tb("Hello");
std::cout << tb[0]; // 调用non-const TextBlock::operator[]
const TextBlock ctb("World");
std::cout << ctb[0]; // 调用const TextBlock::operator[]
// 调用二
void print(const TextBlock& ctb) {
std::cout << ctb[0]; // 调用const TextBlock::operator[]
...
}
// 调用三
std::cout << tb[0]; //没问题,读一个non-const TextBlock
tb[0] = 'x'; //没问题,写一个non-const TextBlock
std::cout << ctb[0]; //没问题, 读一个const TextBlock
ctb[0] = 'x'; //错误,写一个const TextBlock, 错误的原因在于operator[]的返回值为const
注意以上两个函数的返回值都为&,如果返回值是一个char的话,tb[0]= ‘x’;是无法通过编译的;
那是因为,如果函数的返回类型是个内置类型,那么改动函数返回值从来就不合法。纵使合法,C++以by value返回对象这个事实意味被改动的其实是tb.text[0]的一个副本,不是tb.text[0]自身,那不会是你想要的行为。
场景六 bitwise constness和logical constness
class CTextBlock {
public:
...
char& operator[](std::size_t position) const //bitwise const 声明,但其实不适当
private:
char* pText;
}
// 调用
const CTextBlock cctb("Hello"); // 声明一个常量对象
char* pc = &cctb[0]; // 调用const operator[]取得一个指针,指向cctb的数据
*pc = 'J'; // cctb现在有了"Jello"这样的内容
// 说明
// const 修饰函数体,说明函数体内不能修改任何non-static成员变量,在函数题内却是没有修改成员变量,但是最后还是修改成功了,那是因为返回值不是char;bitwise constness的主张是成员变量一个bit都不能修改,以上情况导出所谓的logical constness。
class CTextBlock {
public:
...
std::size_t length() const;
private:
char* pText;
std::size_t textLength; //最近一次计算的文本区块长度
bool lengthIsValid; //目前的长度是否有效
};
// 成员函数实现
std::size_t length() const {
if (!lengthIsValid) {
textLength = std::strlen(pText); //错误,在const成员函数内不能赋值给textLength和lengthIsValid
lengthValid = true;
}
return textLength;
}
场景七 mutable用法
// 用mutable(可变的)释放掉non-static成员变量的bitwise constness约束
class CTextBlock {
public:
...
std::size_t length() const;
private:
char* pText;
mutable std::size_t textLength; //这些成员变量可能总是被更改,即使在const成员函数内。
mutable bool lengthIsValid;
};
std::size_t CTextBlock::length() const {
if (!lengthIsValid) {
textLength = std::strlen(pText);
lengthIsValid = true;
}
return textLength;
}
场景八 const实现non-const成员函数
在const和non-const成员函数中避免重复
class TextBlock {
public:
...
const char& operator[](std::size_t position) const {
... // 边界检查
... // 日志记录数据
... // 检验数据完整性
return text[position];
}
char& operator[](std::size_t position) {
... // 边界检查
... // 日志记录数据
... // 检验数据完整性
return text[position];
}
private:
std::string text;
};
// 可以看到以上有非常严重的代码重复, 改进就是用const operator[] 实现 non-const operator[]
class TextBlock {
public:
...
const char& operator[](std::size_t position) const {
...
...
...
return text[position];
}
char& operator[](std::size_t position) {
return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
// const_cast转型是因为返回类型,static_cast转型是为了转成const对象。
}
};
总结
- 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
- 编译器强制实施bitwise constness,但你编写程序时应该使用"概念上的常量性(conceptual constness)"。
- 当const和non-const 成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复.
Effective C++ 条款03:尽可能使用const的更多相关文章
- Effective C++ -----条款03:尽可能使用const
如果关键字const出现在星号左边,表示被指物是常量:如果出现在星号右边,表示指针自身是常量:如果出现在星号两边,表示被指物和指针两者都是常量. char greeting[] = " he ...
- 《Effective C++》读书笔记 条款03 尽可能使用const 使代码更加健壮
如果你对const足够了解,只需记住以下结论即可: 将某些东西声明为const可帮助编译器侦测出错误用法,const可被施加于任何作用于内的对象.函数参数.函数返回类型.成员函数本体. 编译器强制实施 ...
- 条款03 尽可能使用const
一.概述 使用const约束对象:可以获得编译器的帮助(指出相关出错的地方) const与成员函数:const重载.转型.避免代码重复 二.细节 1. 为什么有些函数要返回const对象(看上去没必要 ...
- Effective C++ 条款三 尽可能使用const
参考资料:http://blog.csdn.net/bizhu12/article/details/6672723 const的常用用法小结 1.用于定义常量变量,这样这个变量在后面就不可以 ...
- Effective C++_笔记_条款03_尽可能使用const
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 关键字const多才多艺,语法变化多端.关于const的基本用法 ...
- 条款21: 尽可能使用const
对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const,还有,两者都不指定为const: char *p = "hello"; ...
- effective c++(03)之const使用方法
char greeting[] = "hello"; char* p = greeting; //non-const pointer,non-const data const ch ...
- 《Effective C++ 》学习笔记——条款03
***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...
- Effective C++ 之 Item 3:尽可能使用 const
Effective C++ Chapter 1. 让自己习惯C++(Accustoming Yourself to C++) Item 3. 尽可能使用 const (Use const whenev ...
随机推荐
- Scala 中我们长见到=> 解析下
=>这符号其实是映射转化的意思,个人理解,可能不准确, var increase = (x: Int) => x + 1 increase(10) res0: Int = 11 意思就是你 ...
- Visualizing wave interference using FireMonkey(很美)
Visualizing wave interference using FireMonkey By: Anders Ohlsson Abstract: This article discusses ...
- 使用from __future__ import unicode_literals时要注意的问题
add by zhj: 在Python中有些库的接口要求参数必须是str类型字符串,有些接口要求参数必须是unicode类型字符串.对于str类型的字符串,调用len()和遍历时,其实都是以字节为单位 ...
- django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)
在python的开发中,遇到了这个错误: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TA ...
- Android_Kotlin 代码学习
https://github.com/ldm520/Android_Kotlin_Demo
- 【Navicat连接Oracle数据库】-Navicat连接Oracle数据库设置
1.navicat连接数据配置信息如下图所示: 点击"确定"按钮,进入到软件 按照图中所画的步骤顺序操作,最后重新启动navicat就可. 关于里面的这个文件夹 insta ...
- 用仿ActionScript的语法来编写html5——第四篇,继承与简单的rpg
第四篇,继承与简单的rpg 这次用继承自LSprite的类来实现简单的rpg的demo先看一下最后的代码与as的相似度 var backLayer; //地图 var mapimg; //人物 var ...
- RS232串口通信
RS232串口经常使用在PC机与FPGA通信中,用于两者之间的数据传输,因为UART协议简单.易实现,故经常使用. DB9接口只需要使用3根线,RXD(2).TXD(3)和GND(5),如下图所示.而 ...
- 怎么找出解析失败的sql
本文由我和公司同事问心共同测试分析完成. 很多时候我们会有这样一个误区,语法错误或者对象不存在应该在语法语义检查这个步骤就结束了,怎么还会存在共享池里面呢?带着这个几个问题我们做几个简单的测试. 我们 ...
- day3-python的基础类源码解析——collection类
1.计数器(counter) Counter是对字典类型的补充,用于追踪值的出现次数. ps:具备字典的所有功能 + 自己的功能 我们从中挑选一些相对常用的方法来举例: 在上面的例子我们可以看出,co ...